jdk

Форк
0
597 строк · 18.5 Кб
1
/*
2
 * Copyright (c) 2001, 2022, 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 "jni.h"
27
#include "jni_util.h"
28
#include "jvm.h"
29
#include "io_util.h"
30
#include "io_util_md.h"
31
#include <stdio.h>
32
#include <windows.h>
33

34
#include <wchar.h>
35
#include <io.h>
36
#include <fcntl.h>
37
#include <errno.h>
38
#include <string.h>
39
#include <sys/types.h>
40
#include <sys/stat.h>
41
#include <limits.h>
42
#include <wincon.h>
43

44

45
static DWORD MAX_INPUT_EVENTS = 2000;
46

47
/* If this returns NULL then an exception is pending */
48
WCHAR*
49
fileToNTPath(JNIEnv *env, jobject file, jfieldID id) {
50
    jstring path = NULL;
51
    if (file != NULL) {
52
        path = (*env)->GetObjectField(env, file, id);
53
    }
54
    return pathToNTPath(env, path, JNI_FALSE);
55
}
56

57
/* Returns the working directory for the given drive, or NULL */
58
WCHAR*
59
currentDir(int di) {
60
    UINT dt;
61
    WCHAR root[4];
62
    // verify drive is valid as _wgetdcwd in the VC++ 2010 runtime
63
    // library does not handle invalid drives.
64
    root[0] = L'A' + (WCHAR)(di - 1);
65
    root[1] = L':';
66
    root[2] = L'\\';
67
    root[3] = L'\0';
68
    dt = GetDriveTypeW(root);
69
    if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) {
70
        return NULL;
71
    } else {
72
        return _wgetdcwd(di, NULL, MAX_PATH);
73
    }
74
}
75

76
/* We cache the length of current working dir here to avoid
77
   calling _wgetcwd() every time we need to resolve a relative
78
   path. This piece of code needs to be revisited if chdir
79
   makes its way into java runtime.
80
*/
81

82
int
83
currentDirLength(const WCHAR* ps, int pathlen) {
84
    WCHAR *dir;
85
    if (pathlen > 2 && ps[1] == L':' && ps[2] != L'\\') {
86
        //drive-relative
87
        WCHAR d = ps[0];
88
        int dirlen = 0;
89
        int di = 0;
90
        if ((d >= L'a') && (d <= L'z')) di = d - L'a' + 1;
91
        else if ((d >= L'A') && (d <= L'Z')) di = d - L'A' + 1;
92
        else return 0; /* invalid drive name. */
93
        dir = currentDir(di);
94
        if (dir != NULL){
95
            dirlen = (int)wcslen(dir);
96
            free(dir);
97
        }
98
        return dirlen;
99
    } else {
100
        static int curDirLenCached = -1;
101
        //relative to both drive and directory
102
        if (curDirLenCached == -1) {
103
            dir = _wgetcwd(NULL, MAX_PATH);
104
            if (dir != NULL) {
105
                curDirLenCached = (int)wcslen(dir);
106
                free(dir);
107
            }
108
        }
109
        return curDirLenCached;
110
    }
111
}
112

113
/*
114
  The "abpathlen" is the size of the buffer needed by _wfullpath. If the
115
  "path" is a relative path, it is "the length of the current dir" + "the
116
  length of the path", if it's "absolute" already, it's the same as
117
  pathlen which is the length of "path".
118
 */
119
WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) {
120
    WCHAR* pathbuf = NULL;
121
    WCHAR* abpath = NULL;
122

123
    abpathlen += 10;  //padding
124
    abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));
125
    if (abpath) {
126
        /* Collapse instances of "foo\.." and ensure absoluteness before
127
           going down to prefixing.
128
        */
129
        if (_wfullpath(abpath, path, abpathlen)) {
130
            pathbuf = getPrefixed(abpath, abpathlen);
131
        } else {
132
            /* _wfullpath fails if the pathlength exceeds 32k wchar.
133
               Instead of doing more fancy things we simply copy the
134
               ps into the return buffer, the subsequent win32 API will
135
               probably fail with FileNotFoundException, which is expected
136
            */
137
            pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
138
            if (pathbuf != 0) {
139
                wcscpy(pathbuf, path);
140
            }
141
        }
142
        free(abpath);
143
    }
144
    return pathbuf;
145
}
146

147
/* If this returns NULL then an exception is pending */
148
WCHAR*
149
pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {
150
    int pathlen = 0;
151
    WCHAR *pathbuf = NULL;
152
    int max_path = 248; /* CreateDirectoryW() has the limit of 248 */
153

154
    WITH_UNICODE_STRING(env, path, ps) {
155
        pathlen = (int)wcslen(ps);
156
        if (pathlen != 0) {
157
            if (pathlen > 2 &&
158
                (ps[0] == L'\\' && ps[1] == L'\\' ||   //UNC
159
                 ps[1] == L':' && ps[2] == L'\\'))     //absolute
160
            {
161
                 if (pathlen > max_path - 1) {
162
                     pathbuf = prefixAbpath(ps, pathlen, pathlen);
163
                 } else {
164
                     pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
165
                     if (pathbuf != 0) {
166
                         wcscpy(pathbuf, ps);
167
                     }
168
                 }
169
            } else {
170
                /* If the path came in as a relative path, need to verify if
171
                   its absolute form is bigger than max_path or not, if yes
172
                   need to (1)convert it to absolute and (2)prefix. This is
173
                   obviously a burden to all relative paths (The current dir/len
174
                   for "drive & directory" relative path is cached, so we only
175
                   calculate it once but for "drive-relative path we call
176
                   _wgetdcwd() and wcslen() every time), but a hit we have
177
                   to take if we want to support relative path beyond max_path.
178
                   There is no way to predict how long the absolute path will be
179
                   (therefore allocate the sufficient memory block) before calling
180
                   _wfullpath(), we have to get the length of "current" dir first.
181
                */
182
                int dirlen = currentDirLength(ps, pathlen);
183
                if (dirlen + pathlen + 1 > max_path - 1) {
184
                    pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);
185
                } else {
186
                    pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
187
                    if (pathbuf != 0) {
188
                        wcscpy(pathbuf, ps);
189
                    }
190
                }
191
            }
192
        }
193
    } END_UNICODE_STRING(env, ps);
194

195
    if (pathlen == 0) {
196
        if (throwFNFE == JNI_TRUE) {
197
            if (!(*env)->ExceptionCheck(env)) {
198
                throwFileNotFoundException(env, path);
199
            }
200
            return NULL;
201
        } else {
202
            pathbuf = (WCHAR*)malloc(sizeof(WCHAR));
203
            if (pathbuf != NULL) {
204
                pathbuf[0] = L'\0';
205
            }
206
        }
207
    }
208
    if (pathbuf == 0) {
209
        JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
210
    }
211
    return pathbuf;
212
}
213

214
FD winFileHandleOpen(JNIEnv *env, jstring path, int flags)
215
{
216
    const DWORD access =
217
        (flags & O_WRONLY) ?  GENERIC_WRITE :
218
        (flags & O_RDWR)   ? (GENERIC_READ | GENERIC_WRITE) :
219
        GENERIC_READ;
220
    const DWORD sharing =
221
        FILE_SHARE_READ | FILE_SHARE_WRITE;
222
    const DWORD disposition =
223
        /* Note: O_TRUNC overrides O_CREAT */
224
        (flags & O_TRUNC) ? CREATE_ALWAYS :
225
        (flags & O_CREAT) ? OPEN_ALWAYS   :
226
        OPEN_EXISTING;
227
    const DWORD  maybeWriteThrough =
228
        (flags & (O_SYNC | O_DSYNC)) ?
229
        FILE_FLAG_WRITE_THROUGH :
230
        FILE_ATTRIBUTE_NORMAL;
231
    const DWORD maybeDeleteOnClose =
232
        (flags & O_TEMPORARY) ?
233
        FILE_FLAG_DELETE_ON_CLOSE :
234
        FILE_ATTRIBUTE_NORMAL;
235
    const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
236
    HANDLE h = NULL;
237

238
    WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
239
    if (pathbuf == NULL) {
240
        /* Exception already pending */
241
        return -1;
242
    }
243
    h = CreateFileW(
244
        pathbuf,            /* Wide char path name */
245
        access,             /* Read and/or write permission */
246
        sharing,            /* File sharing flags */
247
        NULL,               /* Security attributes */
248
        disposition,        /* creation disposition */
249
        flagsAndAttributes, /* flags and attributes */
250
        NULL);
251
    free(pathbuf);
252

253
    if (h == INVALID_HANDLE_VALUE) {
254
        throwFileNotFoundException(env, path);
255
        return -1;
256
    }
257
    return (jlong) h;
258
}
259

260
FD getFD(JNIEnv *env, jobject obj, jfieldID fid) {
261
  jobject fdo = (*env)->GetObjectField(env, obj, fid);
262
  if (fdo == NULL) {
263
    return -1;
264
  }
265
  return (*env)->GetLongField(env, fdo, IO_handle_fdID);
266
}
267

268
void
269
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
270
{
271
    FD h = winFileHandleOpen(env, path, flags);
272
    if (h >= 0) {
273
        jobject fdobj;
274
        jboolean append;
275
        fdobj = (*env)->GetObjectField(env, this, fid);
276
        if (fdobj != NULL) {
277
            // Set FD
278
            (*env)->SetLongField(env, fdobj, IO_handle_fdID, h);
279
            append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
280
            (*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
281
        }
282
    }
283
}
284

285
/* These are functions that use a handle fd instead of the
286
   old C style int fd as is used in HPI layer */
287

288
static int
289
handleNonSeekAvailable(FD, long *);
290
static int
291
handleStdinAvailable(FD, long *);
292

293
int
294
handleAvailable(FD fd, jlong *pbytes) {
295
    HANDLE h = (HANDLE)fd;
296
    DWORD type = 0;
297

298
    type = GetFileType(h);
299
    /* Handle is for keyboard or pipe */
300
    if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {
301
        int ret;
302
        long lpbytes;
303
        HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);
304
        if (stdInHandle == h) {
305
            ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */
306
        } else {
307
            ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */
308
        }
309
        (*pbytes) = (jlong)(lpbytes);
310
        return ret;
311
    }
312
    /* Handle is for regular file */
313
    if (type == FILE_TYPE_DISK) {
314
        jlong current, end;
315

316
        LARGE_INTEGER filesize;
317
        current = handleLseek(fd, 0, SEEK_CUR);
318
        if (current < 0) {
319
            return FALSE;
320
        }
321
        if (GetFileSizeEx(h, &filesize) == 0) {
322
            return FALSE;
323
        }
324
        end = long_to_jlong(filesize.QuadPart);
325
        *pbytes = end - current;
326
        return TRUE;
327
    }
328
    return FALSE;
329
}
330

331
static int
332
handleNonSeekAvailable(FD fd, long *pbytes) {
333
    /* This is used for available on non-seekable devices
334
     * (like both named and anonymous pipes, such as pipes
335
     *  connected to an exec'd process).
336
     * Standard Input is a special case.
337
     *
338
     */
339
    HANDLE han;
340

341
    if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {
342
        return FALSE;
343
    }
344

345
    if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {
346
        /* PeekNamedPipe fails when at EOF.  In that case we
347
         * simply make *pbytes = 0 which is consistent with the
348
         * behavior we get on Solaris when an fd is at EOF.
349
         * The only alternative is to raise and Exception,
350
         * which isn't really warranted.
351
         */
352
        if (GetLastError() != ERROR_BROKEN_PIPE) {
353
            return FALSE;
354
        }
355
        *pbytes = 0;
356
    }
357
    return TRUE;
358
}
359

360
static int
361
handleStdinAvailable(FD fd, long *pbytes) {
362
    HANDLE han;
363
    DWORD numEventsRead = 0;    /* Number of events read from buffer */
364
    DWORD numEvents = 0;        /* Number of events in buffer */
365
    DWORD i = 0;                /* Loop index */
366
    DWORD curLength = 0;        /* Position marker */
367
    DWORD actualLength = 0;     /* Number of bytes readable */
368
    BOOL error = FALSE;         /* Error holder */
369
    INPUT_RECORD *lpBuffer;     /* Pointer to records of input events */
370
    DWORD bufferSize = 0;
371

372
    if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
373
        return FALSE;
374
    }
375

376
    /* Construct an array of input records in the console buffer */
377
    error = GetNumberOfConsoleInputEvents(han, &numEvents);
378
    if (error == 0) {
379
        return handleNonSeekAvailable(fd, pbytes);
380
    }
381

382
    /* lpBuffer must fit into 64K or else PeekConsoleInput fails */
383
    if (numEvents > MAX_INPUT_EVENTS) {
384
        numEvents = MAX_INPUT_EVENTS;
385
    }
386

387
    bufferSize = numEvents * sizeof(INPUT_RECORD);
388
    if (bufferSize == 0)
389
        bufferSize = 1;
390
    lpBuffer = malloc(bufferSize);
391
    if (lpBuffer == NULL) {
392
        return FALSE;
393
    }
394

395
    error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);
396
    if (error == 0) {
397
        free(lpBuffer);
398
        return FALSE;
399
    }
400

401
    /* Examine input records for the number of bytes available */
402
    for(i=0; i<numEvents; i++) {
403
        if (lpBuffer[i].EventType == KEY_EVENT) {
404
            KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)
405
                                          &(lpBuffer[i].Event);
406
            if (keyRecord->bKeyDown == TRUE) {
407
                CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);
408
                curLength++;
409
                if (*keyPressed == '\r')
410
                    actualLength = curLength;
411
            }
412
        }
413
    }
414
    if(lpBuffer != NULL)
415
        free(lpBuffer);
416
    *pbytes = (long) actualLength;
417
    return TRUE;
418
}
419

420
/*
421
 * This is documented to succeed on read-only files, but Win32's
422
 * FlushFileBuffers functions fails with "access denied" in such a
423
 * case.  So we only signal an error if the error is *not* "access
424
 * denied".
425
 */
426

427
int
428
handleSync(FD fd) {
429
    /*
430
     * From the documentation:
431
     *
432
     *     On Windows NT, the function FlushFileBuffers fails if hFile
433
     *     is a handle to console output. That is because console
434
     *     output is not buffered. The function returns FALSE, and
435
     *     GetLastError returns ERROR_INVALID_HANDLE.
436
     *
437
     * On the other hand, on Win95, it returns without error.  I cannot
438
     * assume that 0, 1, and 2 are console, because if someone closes
439
     * System.out and then opens a file, they might get file descriptor
440
     * 1.  An error on *that* version of 1 should be reported, whereas
441
     * an error on System.out (which was the original 1) should be
442
     * ignored.  So I use isatty() to ensure that such an error was due
443
     * to this bogosity, and if it was, I ignore the error.
444
     */
445

446
    HANDLE handle = (HANDLE)fd;
447

448
    if (!FlushFileBuffers(handle)) {
449
        if (GetLastError() != ERROR_ACCESS_DENIED) {    /* from winerror.h */
450
            return -1;
451
        }
452
    }
453
    return 0;
454
}
455

456
jint
457
handleSetLength(FD fd, jlong length) {
458
    HANDLE h = (HANDLE)fd;
459
    FILE_END_OF_FILE_INFO eofInfo;
460

461
    eofInfo.EndOfFile.QuadPart = length;
462

463
    if (h == INVALID_HANDLE_VALUE) {
464
        return -1;
465
    }
466
    if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &eofInfo,
467
            sizeof(FILE_END_OF_FILE_INFO))) {
468
        return -1;
469
    }
470
    return 0;
471
}
472

473
JNIEXPORT
474
jint
475
handleRead(FD fd, void *buf, jint len)
476
{
477
    DWORD read = 0;
478
    BOOL result = 0;
479
    HANDLE h = (HANDLE)fd;
480
    if (h == INVALID_HANDLE_VALUE) {
481
        return -1;
482
    }
483
    result = ReadFile(h,          /* File handle to read */
484
                      buf,        /* address to put data */
485
                      len,        /* number of bytes to read */
486
                      &read,      /* number of bytes read */
487
                      NULL);      /* no overlapped struct */
488
    if (result == 0) {
489
        int error = GetLastError();
490
        if (error == ERROR_BROKEN_PIPE) {
491
            return 0; /* EOF */
492
        }
493
        return -1;
494
    }
495
    return (jint)read;
496
}
497

498
static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)
499
{
500
    BOOL result = 0;
501
    DWORD written = 0;
502
    HANDLE h = (HANDLE)fd;
503
    if (h != INVALID_HANDLE_VALUE) {
504
        OVERLAPPED ov;
505
        LPOVERLAPPED lpOv;
506
        if (append == JNI_TRUE) {
507
            ov.Offset = (DWORD)0xFFFFFFFF;
508
            ov.OffsetHigh = (DWORD)0xFFFFFFFF;
509
            ov.hEvent = NULL;
510
            lpOv = &ov;
511
        } else {
512
            lpOv = NULL;
513
        }
514
        result = WriteFile(h,                /* File handle to write */
515
                           buf,              /* pointers to the buffers */
516
                           len,              /* number of bytes to write */
517
                           &written,         /* receives number of bytes written */
518
                           lpOv);            /* overlapped struct */
519
    }
520
    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
521
        return -1;
522
    }
523
    return (jint)written;
524
}
525

526
jint handleWrite(FD fd, const void *buf, jint len) {
527
    return writeInternal(fd, buf, len, JNI_FALSE);
528
}
529

530
jint handleAppend(FD fd, const void *buf, jint len) {
531
    return writeInternal(fd, buf, len, JNI_TRUE);
532
}
533

534
// Function to close the fd held by this FileDescriptor and set fd to -1.
535
void
536
fileDescriptorClose(JNIEnv *env, jobject this)
537
{
538
    FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
539
    HANDLE h = (HANDLE)fd;
540
    if ((*env)->ExceptionOccurred(env)) {
541
        return;
542
    }
543

544
    if (h == INVALID_HANDLE_VALUE) {
545
        return;
546
    }
547

548
    /* Set the fd to -1 before closing it so that the timing window
549
     * of other threads using the wrong fd (closed but recycled fd,
550
     * that gets re-opened with some other filename) is reduced.
551
     * Practically the chance of its occurrence is low, however, we are
552
     * taking extra precaution over here.
553
     */
554
    (*env)->SetLongField(env, this, IO_handle_fdID, -1);
555
    if ((*env)->ExceptionOccurred(env)) {
556
        return;
557
    }
558

559
    if (CloseHandle(h) == 0) { /* Returns zero on failure */
560
        JNU_ThrowIOExceptionWithLastError(env, "close failed");
561
    }
562
}
563

564
JNIEXPORT jlong JNICALL
565
handleLseek(FD fd, jlong offset, jint whence)
566
{
567
    LARGE_INTEGER pos, distance;
568
    DWORD op = FILE_CURRENT;
569
    HANDLE h = (HANDLE)fd;
570

571
    if (whence == SEEK_END) {
572
        op = FILE_END;
573
    }
574
    if (whence == SEEK_CUR) {
575
        op = FILE_CURRENT;
576
    }
577
    if (whence == SEEK_SET) {
578
        op = FILE_BEGIN;
579
    }
580

581
    distance.QuadPart = offset;
582
    if (SetFilePointerEx(h, distance, &pos, op) == 0) {
583
        return -1;
584
    }
585
    return long_to_jlong(pos.QuadPart);
586
}
587

588
jlong
589
handleGetLength(FD fd) {
590
    HANDLE h = (HANDLE) fd;
591
    LARGE_INTEGER length;
592
    if (GetFileSizeEx(h, &length) != 0) {
593
        return long_to_jlong(length.QuadPart);
594
    } else {
595
        return -1;
596
    }
597
}
598

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

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

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

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