Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/io/io_util_md.c
32287 views
/*1* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "jni.h"26#include "jni_util.h"27#include "jvm.h"28#include "io_util.h"29#include "io_util_md.h"30#include <stdio.h>31#include <windows.h>3233#include <wchar.h>34#include <io.h>35#include <fcntl.h>36#include <errno.h>37#include <string.h>38#include <sys/types.h>39#include <sys/stat.h>40#include <limits.h>41#include <wincon.h>424344static DWORD MAX_INPUT_EVENTS = 2000;4546/* If this returns NULL then an exception is pending */47WCHAR*48fileToNTPath(JNIEnv *env, jobject file, jfieldID id) {49jstring path = NULL;50if (file != NULL) {51path = (*env)->GetObjectField(env, file, id);52}53return pathToNTPath(env, path, JNI_FALSE);54}5556/* Returns the working directory for the given drive, or NULL */57WCHAR*58currentDir(int di) {59UINT dt;60WCHAR root[4];61// verify drive is valid as _wgetdcwd in the VC++ 2010 runtime62// library does not handle invalid drives.63root[0] = L'A' + (WCHAR)(di - 1);64root[1] = L':';65root[2] = L'\\';66root[3] = L'\0';67dt = GetDriveTypeW(root);68if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) {69return NULL;70} else {71return _wgetdcwd(di, NULL, MAX_PATH);72}73}7475/* We cache the length of current working dir here to avoid76calling _wgetcwd() every time we need to resolve a relative77path. This piece of code needs to be revisited if chdir78makes its way into java runtime.79*/8081int82currentDirLength(const WCHAR* ps, int pathlen) {83WCHAR *dir;84if (pathlen > 2 && ps[1] == L':' && ps[2] != L'\\') {85//drive-relative86WCHAR d = ps[0];87int dirlen = 0;88int di = 0;89if ((d >= L'a') && (d <= L'z')) di = d - L'a' + 1;90else if ((d >= L'A') && (d <= L'Z')) di = d - L'A' + 1;91else return 0; /* invalid drive name. */92dir = currentDir(di);93if (dir != NULL){94dirlen = (int)wcslen(dir);95free(dir);96}97return dirlen;98} else {99static int curDirLenCached = -1;100//relative to both drive and directory101if (curDirLenCached == -1) {102int dirlen = -1;103dir = _wgetcwd(NULL, MAX_PATH);104if (dir != NULL) {105curDirLenCached = (int)wcslen(dir);106free(dir);107}108}109return curDirLenCached;110}111}112113/*114The "abpathlen" is the size of the buffer needed by _wfullpath. If the115"path" is a relative path, it is "the length of the current dir" + "the116length of the path", if it's "absolute" already, it's the same as117pathlen which is the length of "path".118*/119WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) {120WCHAR* pathbuf = NULL;121WCHAR* abpath = NULL;122123abpathlen += 10; //padding124abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));125if (abpath) {126/* Collapse instances of "foo\.." and ensure absoluteness before127going down to prefixing.128*/129if (_wfullpath(abpath, path, abpathlen)) {130pathbuf = getPrefixed(abpath, abpathlen);131} else {132/* _wfullpath fails if the pathlength exceeds 32k wchar.133Instead of doing more fancy things we simply copy the134ps into the return buffer, the subsequent win32 API will135probably fail with FileNotFoundException, which is expected136*/137pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));138if (pathbuf != 0) {139wcscpy(pathbuf, path);140}141}142free(abpath);143}144return pathbuf;145}146147/* If this returns NULL then an exception is pending */148WCHAR*149pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {150int pathlen = 0;151WCHAR *pathbuf = NULL;152int max_path = 248; /* CreateDirectoryW() has the limit of 248 */153154WITH_UNICODE_STRING(env, path, ps) {155pathlen = (int)wcslen(ps);156if (pathlen != 0) {157if (pathlen > 2 &&158(ps[0] == L'\\' && ps[1] == L'\\' || //UNC159ps[1] == L':' && ps[2] == L'\\')) //absolute160{161if (pathlen > max_path - 1) {162pathbuf = prefixAbpath(ps, pathlen, pathlen);163if (pathbuf == NULL) {164JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");165return NULL;166}167} else {168pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));169if (pathbuf != 0) {170wcscpy(pathbuf, ps);171}172}173} else {174/* If the path came in as a relative path, need to verify if175its absolute form is bigger than max_path or not, if yes176need to (1)convert it to absolute and (2)prefix. This is177obviously a burden to all relative paths (The current dir/len178for "drive & directory" relative path is cached, so we only179calculate it once but for "drive-relative path we call180_wgetdcwd() and wcslen() everytime), but a hit we have181to take if we want to support relative path beyond max_path.182There is no way to predict how long the absolute path will be183(therefor allocate the sufficient memory block) before calling184_wfullpath(), we have to get the length of "current" dir first.185*/186WCHAR *abpath = NULL;187int dirlen = currentDirLength(ps, pathlen);188if (dirlen + pathlen + 1 > max_path - 1) {189pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);190if (pathbuf == NULL) {191JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");192return NULL;193}194} else {195pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));196if (pathbuf != 0) {197wcscpy(pathbuf, ps);198}199}200}201}202} END_UNICODE_STRING(env, ps);203204if (pathlen == 0) {205if (throwFNFE == JNI_TRUE) {206if (!(*env)->ExceptionCheck(env)) {207throwFileNotFoundException(env, path);208}209return NULL;210} else {211pathbuf = (WCHAR*)malloc(sizeof(WCHAR));212if (pathbuf != NULL) {213pathbuf[0] = L'\0';214}215}216}217if (pathbuf == 0) {218if (!(*env)->ExceptionCheck(env)) {219JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");220}221}222return pathbuf;223}224225FD226winFileHandleOpen(JNIEnv *env, jstring path, int flags)227{228const DWORD access =229(flags & O_WRONLY) ? GENERIC_WRITE :230(flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) :231GENERIC_READ;232const DWORD sharing =233FILE_SHARE_READ | FILE_SHARE_WRITE;234const DWORD disposition =235/* Note: O_TRUNC overrides O_CREAT */236(flags & O_TRUNC) ? CREATE_ALWAYS :237(flags & O_CREAT) ? OPEN_ALWAYS :238OPEN_EXISTING;239const DWORD maybeWriteThrough =240(flags & (O_SYNC | O_DSYNC)) ?241FILE_FLAG_WRITE_THROUGH :242FILE_ATTRIBUTE_NORMAL;243const DWORD maybeDeleteOnClose =244(flags & O_TEMPORARY) ?245FILE_FLAG_DELETE_ON_CLOSE :246FILE_ATTRIBUTE_NORMAL;247const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;248HANDLE h = NULL;249250WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);251if (pathbuf == NULL) {252/* Exception already pending */253return -1;254}255h = CreateFileW(256pathbuf, /* Wide char path name */257access, /* Read and/or write permission */258sharing, /* File sharing flags */259NULL, /* Security attributes */260disposition, /* creation disposition */261flagsAndAttributes, /* flags and attributes */262NULL);263free(pathbuf);264265if (h == INVALID_HANDLE_VALUE) {266throwFileNotFoundException(env, path);267return -1;268}269return (jlong) h;270}271272void273fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)274{275FD h = winFileHandleOpen(env, path, flags);276if (h >= 0) {277SET_FD(this, h, fid);278}279}280281/* These are functions that use a handle fd instead of the282old C style int fd as is used in HPI layer */283284static int285handleNonSeekAvailable(FD, long *);286static int287handleStdinAvailable(FD, long *);288289int290handleAvailable(FD fd, jlong *pbytes) {291HANDLE h = (HANDLE)fd;292DWORD type = 0;293294type = GetFileType(h);295/* Handle is for keyboard or pipe */296if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE) {297int ret;298long lpbytes;299HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE);300if (stdInHandle == h) {301ret = handleStdinAvailable(fd, &lpbytes); /* keyboard */302} else {303ret = handleNonSeekAvailable(fd, &lpbytes); /* pipe */304}305(*pbytes) = (jlong)(lpbytes);306return ret;307}308/* Handle is for regular file */309if (type == FILE_TYPE_DISK) {310jlong current, end;311312LARGE_INTEGER filesize;313current = handleLseek(fd, 0, SEEK_CUR);314if (current < 0) {315return FALSE;316}317if (GetFileSizeEx(h, &filesize) == 0) {318return FALSE;319}320end = long_to_jlong(filesize.QuadPart);321*pbytes = end - current;322return TRUE;323}324return FALSE;325}326327static int328handleNonSeekAvailable(FD fd, long *pbytes) {329/* This is used for available on non-seekable devices330* (like both named and anonymous pipes, such as pipes331* connected to an exec'd process).332* Standard Input is a special case.333*334*/335HANDLE han;336337if ((han = (HANDLE) fd) == INVALID_HANDLE_VALUE) {338return FALSE;339}340341if (! PeekNamedPipe(han, NULL, 0, NULL, pbytes, NULL)) {342/* PeekNamedPipe fails when at EOF. In that case we343* simply make *pbytes = 0 which is consistent with the344* behavior we get on Solaris when an fd is at EOF.345* The only alternative is to raise and Exception,346* which isn't really warranted.347*/348if (GetLastError() != ERROR_BROKEN_PIPE) {349return FALSE;350}351*pbytes = 0;352}353return TRUE;354}355356static int357handleStdinAvailable(FD fd, long *pbytes) {358HANDLE han;359DWORD numEventsRead = 0; /* Number of events read from buffer */360DWORD numEvents = 0; /* Number of events in buffer */361DWORD i = 0; /* Loop index */362DWORD curLength = 0; /* Position marker */363DWORD actualLength = 0; /* Number of bytes readable */364BOOL error = FALSE; /* Error holder */365INPUT_RECORD *lpBuffer; /* Pointer to records of input events */366DWORD bufferSize = 0;367368if ((han = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {369return FALSE;370}371372/* Construct an array of input records in the console buffer */373error = GetNumberOfConsoleInputEvents(han, &numEvents);374if (error == 0) {375return handleNonSeekAvailable(fd, pbytes);376}377378/* lpBuffer must fit into 64K or else PeekConsoleInput fails */379if (numEvents > MAX_INPUT_EVENTS) {380numEvents = MAX_INPUT_EVENTS;381}382383bufferSize = numEvents * sizeof(INPUT_RECORD);384if (bufferSize == 0)385bufferSize = 1;386lpBuffer = malloc(bufferSize);387if (lpBuffer == NULL) {388return FALSE;389}390391error = PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead);392if (error == 0) {393free(lpBuffer);394return FALSE;395}396397/* Examine input records for the number of bytes available */398for(i=0; i<numEvents; i++) {399if (lpBuffer[i].EventType == KEY_EVENT) {400KEY_EVENT_RECORD *keyRecord = (KEY_EVENT_RECORD *)401&(lpBuffer[i].Event);402if (keyRecord->bKeyDown == TRUE) {403CHAR *keyPressed = (CHAR *) &(keyRecord->uChar);404curLength++;405if (*keyPressed == '\r')406actualLength = curLength;407}408}409}410if(lpBuffer != NULL)411free(lpBuffer);412*pbytes = (long) actualLength;413return TRUE;414}415416/*417* This is documented to succeed on read-only files, but Win32's418* FlushFileBuffers functions fails with "access denied" in such a419* case. So we only signal an error if the error is *not* "access420* denied".421*/422423int424handleSync(FD fd) {425/*426* From the documentation:427*428* On Windows NT, the function FlushFileBuffers fails if hFile429* is a handle to console output. That is because console430* output is not buffered. The function returns FALSE, and431* GetLastError returns ERROR_INVALID_HANDLE.432*433* On the other hand, on Win95, it returns without error. I cannot434* assume that 0, 1, and 2 are console, because if someone closes435* System.out and then opens a file, they might get file descriptor436* 1. An error on *that* version of 1 should be reported, whereas437* an error on System.out (which was the original 1) should be438* ignored. So I use isatty() to ensure that such an error was due439* to this bogosity, and if it was, I ignore the error.440*/441442HANDLE handle = (HANDLE)fd;443444if (!FlushFileBuffers(handle)) {445if (GetLastError() != ERROR_ACCESS_DENIED) { /* from winerror.h */446return -1;447}448}449return 0;450}451452453int454handleSetLength(FD fd, jlong length) {455HANDLE h = (HANDLE)fd;456long high = (long)(length >> 32);457DWORD ret;458459if (h == (HANDLE)(-1)) return -1;460ret = SetFilePointer(h, (long)(length), &high, FILE_BEGIN);461if (ret == 0xFFFFFFFF && GetLastError() != NO_ERROR) {462return -1;463}464if (SetEndOfFile(h) == FALSE) return -1;465return 0;466}467468JNIEXPORT469jint470handleRead(FD fd, void *buf, jint len)471{472DWORD read = 0;473BOOL result = 0;474HANDLE h = (HANDLE)fd;475if (h == INVALID_HANDLE_VALUE) {476return -1;477}478result = ReadFile(h, /* File handle to read */479buf, /* address to put data */480len, /* number of bytes to read */481&read, /* number of bytes read */482NULL); /* no overlapped struct */483if (result == 0) {484int error = GetLastError();485if (error == ERROR_BROKEN_PIPE) {486return 0; /* EOF */487}488return -1;489}490return (jint)read;491}492493static jint writeInternal(FD fd, const void *buf, jint len, jboolean append)494{495BOOL result = 0;496DWORD written = 0;497HANDLE h = (HANDLE)fd;498if (h != INVALID_HANDLE_VALUE) {499OVERLAPPED ov;500LPOVERLAPPED lpOv;501if (append == JNI_TRUE) {502ov.Offset = (DWORD)0xFFFFFFFF;503ov.OffsetHigh = (DWORD)0xFFFFFFFF;504ov.hEvent = NULL;505lpOv = &ov;506} else {507lpOv = NULL;508}509result = WriteFile(h, /* File handle to write */510buf, /* pointers to the buffers */511len, /* number of bytes to write */512&written, /* receives number of bytes written */513lpOv); /* overlapped struct */514}515if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {516return -1;517}518return (jint)written;519}520521jint handleWrite(FD fd, const void *buf, jint len) {522return writeInternal(fd, buf, len, JNI_FALSE);523}524525jint handleAppend(FD fd, const void *buf, jint len) {526return writeInternal(fd, buf, len, JNI_TRUE);527}528529jint530handleClose(JNIEnv *env, jobject this, jfieldID fid)531{532FD fd = GET_FD(this, fid);533HANDLE h = (HANDLE)fd;534535if (h == INVALID_HANDLE_VALUE) {536return 0;537}538539/* Set the fd to -1 before closing it so that the timing window540* of other threads using the wrong fd (closed but recycled fd,541* that gets re-opened with some other filename) is reduced.542* Practically the chance of its occurance is low, however, we are543* taking extra precaution over here.544*/545SET_FD(this, -1, fid);546547if (CloseHandle(h) == 0) { /* Returns zero on failure */548JNU_ThrowIOExceptionWithLastError(env, "close failed");549}550return 0;551}552553jlong554handleLseek(FD fd, jlong offset, jint whence)555{556LARGE_INTEGER pos, distance;557DWORD lowPos = 0;558long highPos = 0;559DWORD op = FILE_CURRENT;560HANDLE h = (HANDLE)fd;561562if (whence == SEEK_END) {563op = FILE_END;564}565if (whence == SEEK_CUR) {566op = FILE_CURRENT;567}568if (whence == SEEK_SET) {569op = FILE_BEGIN;570}571572distance.QuadPart = offset;573if (SetFilePointerEx(h, distance, &pos, op) == 0) {574return -1;575}576return long_to_jlong(pos.QuadPart);577}578579size_t580getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg)581{582size_t n = 0;583if (cbErrorMsg > 0) {584BOOLEAN noError = FALSE;585WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR));586if (utf16_osErrorMsg == NULL) {587// OOM accident588strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg);589// truncate if too long590utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';591n = strlen(utf8_jvmErrorMsg);592} else {593DWORD errval = GetLastError();594if (errval != 0) {595// WIN32 error596n = (size_t)FormatMessageW(597FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,598NULL,599errval,6000,601utf16_osErrorMsg,602(DWORD)cbErrorMsg,603NULL);604if (n > 3) {605// Drop final '.', CR, LF606if (utf16_osErrorMsg[n - 1] == L'\n') --n;607if (utf16_osErrorMsg[n - 1] == L'\r') --n;608if (utf16_osErrorMsg[n - 1] == L'.') --n;609utf16_osErrorMsg[n] = L'\0';610}611} else if (errno != 0) {612// C runtime error that has no corresponding WIN32 error code613const WCHAR *rtError = _wcserror(errno);614if (rtError != NULL) {615wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg);616// truncate if too long617utf16_osErrorMsg[cbErrorMsg - 1] = L'\0';618n = wcslen(utf16_osErrorMsg);619}620} else621noError = TRUE; //OS has no error to report622623if (!noError) {624if (n > 0) {625n = WideCharToMultiByte(626CP_UTF8,6270,628utf16_osErrorMsg,629n,630utf8_jvmErrorMsg,631cbErrorMsg,632NULL,633NULL);634635// no way to die636if (n > 0)637utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0';638}639640if (n <= 0) {641strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg);642// truncate if too long643utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';644n = strlen(utf8_jvmErrorMsg);645}646}647free(utf16_osErrorMsg);648}649}650return n;651}652653654