< prev index next >

src/java.base/windows/native/libjava/canonicalize_md.c

Print this page
rev 56594 : 8232168: Fix non wide char canonicalization on Windows
Reviewed-by:

*** 1,7 **** /* ! * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 39,81 **** #include <errno.h> #include "io_util_md.h" #undef DEBUG_PATH /* Define this to debug path code */ - #define isfilesep(c) ((c) == '/' || (c) == '\\') #define wisfilesep(c) ((c) == L'/' || (c) == L'\\') - #define islb(c) (IsDBCSLeadByte((BYTE)(c))) /* Copy bytes to dst, not going past dend; return dst + number of bytes copied, or NULL if dend would have been exceeded. If first != '\0', copy that byte before copying bytes from src to send - 1. */ - static char * - cp(char *dst, char *dend, char first, char *src, char *send) - { - char *p = src, *q = dst; - if (first != '\0') { - if (q < dend) { - *q++ = first; - } else { - errno = ENAMETOOLONG; - return NULL; - } - } - if (send - p > dend - q) { - errno = ENAMETOOLONG; - return NULL; - } - while (p < send) { - *q++ = *p++; - } - return q; - } - - /* Wide character version of cp */ - static WCHAR* wcp(WCHAR *dst, WCHAR *dend, WCHAR first, WCHAR *src, WCHAR *send) { WCHAR *p = src, *q = dst; if (first != L'\0') { --- 39,55 ----
*** 97,119 **** /* Find first instance of '\\' at or following start. Return the address of that byte or the address of the null terminator if '\\' is not found. */ - static char * - nextsep(char *start) - { - char *p = start; - int c; - while ((c = *p) && (c != '\\')) { - p += ((islb(c) && p[1]) ? 2 : 1); - } - return p; - } - - /* Wide character version of nextsep */ - static WCHAR * wnextsep(WCHAR *start) { WCHAR *p = start; int c; --- 71,80 ----
*** 123,146 **** } /* Tell whether the given string contains any wildcard characters */ static int - wild(char *start) - { - char *p = start; - int c; - while (c = *p) { - if ((c == '*') || (c == '?')) return 1; - p += ((islb(c) && p[1]) ? 2 : 1); - } - return 0; - } - - /* Wide character version of wild */ - - static int wwild(WCHAR *start) { WCHAR *p = start; int c; while (c = *p) { --- 84,93 ----
*** 155,183 **** In the canonicalized form no path element may have dots at its end. Allowed canonical paths: c:\xa...dksd\..ksa\.lk c:\...a\.b\cd..x.x Prohibited canonical paths: c:\..\x c:\x.\d c:\... */ static int - dots(char *start) - { - char *p = start; - while (*p) { - if ((p = strchr(p, '.')) == NULL) // find next occurrence of '.' - return 0; // no more dots - p++; // next char - while ((*p) == '.') // go to the end of dots - p++; - if (*p && (*p != '\\')) // path element does not end with a dot - p++; // go to the next char - else - return 1; // path element does end with a dot - prohibited - } - return 0; // no prohibited combinations of dots found - } - - /* Wide character version of dots */ - static int wdots(WCHAR *start) { WCHAR *p = start; // Skip "\\.\" prefix if (wcslen(p) > 4 && !wcsncmp(p, L"\\\\.\\", 4)) --- 102,111 ----
*** 231,446 **** have been converted to native form already, via JVM_NativePath(). This is necessary because _fullpath() rejects duplicate separator characters on Win95, though it accepts them on NT. */ int ! canonicalize(char *orig_path, char *result, int size) ! { ! WIN32_FIND_DATA fd; ! HANDLE h; ! char path[1024]; /* Working copy of path */ ! char *src, *dst, *dend; ! wchar_t *worig_path, *wresult; ! size_t converted_chars = 0; ! ! /* handle long path with length >= MAX_PATH */ ! if (strlen(orig_path) >= MAX_PATH) { ! if ((worig_path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) ! return -1; ! ! if (mbstowcs_s(&converted_chars, worig_path, (size_t)size, orig_path, (size_t)(size - 1)) != 0) { ! free(worig_path); ! return -1; ! } ! ! if ((wresult = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) ! return -1; ! ! if (wcanonicalize(worig_path, wresult, size) != 0) { ! free(worig_path); ! free(wresult); ! return -1; ! } ! ! if (wcstombs_s(&converted_chars, result, (size_t)size, wresult, (size_t)(size - 1)) != 0) { ! free(worig_path); ! free(wresult); ! return -1; ! } ! free(worig_path); ! free(wresult); ! return 0; } ! /* Reject paths that contain wildcards */ ! if (wild(orig_path)) { ! errno = EINVAL; ! return -1; ! } ! ! /* Collapse instances of "foo\.." and ensure absoluteness. Note that ! contrary to the documentation, the _fullpath procedure does not require ! the drive to be available. It also does not reliably change all ! occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */ ! if (!_fullpath(path, orig_path, sizeof(path))) { ! return -1; ! } ! ! /* Correction for Win95: _fullpath may leave a trailing "\\" ! on a UNC pathname */ ! if ((path[0] == '\\') && (path[1] == '\\')) { ! char *p = path + strlen(path); ! if ((p[-1] == '\\') && !islb(p[-2])) { ! p[-1] = '\0'; ! } } ! if (dots(path)) /* Check for prohibited combinations of dots */ ! return -1; ! ! src = path; /* Start scanning here */ ! dst = result; /* Place results here */ ! dend = dst + size; /* Don't go to or past here */ ! ! /* Copy prefix, assuming path is absolute */ ! if (isalpha(src[0]) && (src[1] == ':') && (src[2] == '\\')) { ! /* Drive specifier */ ! *src = toupper(*src); /* Canonicalize drive letter */ ! if (!(dst = cp(dst, dend, '\0', src, src + 2))) { ! return -1; ! } ! src += 2; ! } else if ((src[0] == '\\') && (src[1] == '\\')) { ! /* UNC pathname */ ! char *p; ! p = nextsep(src + 2); /* Skip past host name */ ! if (!*p) { ! /* A UNC pathname must begin with "\\\\host\\share", ! so reject this path as invalid if there is no share name */ ! errno = EINVAL; ! return -1; ! } ! p = nextsep(p + 1); /* Skip past share name */ ! if (!(dst = cp(dst, dend, '\0', src, p))) { ! return -1; ! } ! src = p; ! } else { ! /* Invalid path */ ! errno = EINVAL; ! return -1; } ! /* Windows 95/98/Me bug - FindFirstFile fails on network mounted drives */ ! /* for root pathes like "E:\" . If the path has this form, we should */ ! /* simply return it, it is already canonicalized. */ ! if (strlen(path) == 3 && path[1] == ':' && path[2] == '\\') { ! /* At this point we have already copied the drive specifier ("z:")*/ ! /* so we need to copy "\" and the null character. */ ! result[2] = '\\'; ! result[3] = '\0'; ! return 0; ! } ! ! /* At this point we have copied either a drive specifier ("z:") or a UNC ! prefix ("\\\\host\\share") to the result buffer, and src points to the ! first byte of the remainder of the path. We now scan through the rest ! of the path, looking up each prefix in order to find the true name of ! the last element of each prefix, thereby computing the full true name of ! the original path. */ ! while (*src) { ! char *p = nextsep(src + 1); /* Find next separator */ ! char c = *p; ! assert(*src == '\\'); /* Invariant */ ! *p = '\0'; /* Temporarily clear separator */ ! h = FindFirstFile(path, &fd); /* Look up prefix */ ! *p = c; /* Restore separator */ ! if (h != INVALID_HANDLE_VALUE) { ! /* Lookup succeeded; append true name to result and continue */ ! FindClose(h); ! if (!(dst = cp(dst, dend, '\\', ! fd.cFileName, ! fd.cFileName + strlen(fd.cFileName)))) { ! return -1; ! } ! src = p; ! continue; ! } else { ! if (!lastErrorReportable()) { ! if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) { ! return -1; ! } ! break; ! } else { ! return -1; ! } ! } } ! if (dst >= dend) { ! errno = ENAMETOOLONG; ! return -1; } - *dst = '\0'; - return 0; ! } ! ! ! /* Convert a pathname to canonical form. The input prefix is assumed ! to be in canonical form already, and the trailing filename must not ! contain any wildcard, dot/double dot, or other "tricky" characters ! that are rejected by the canonicalize() routine above. This ! routine is present to allow the canonicalization prefix cache to be ! used while still returning canonical names with the correct ! capitalization. */ ! int ! canonicalizeWithPrefix(char* canonicalPrefix, char* pathWithCanonicalPrefix, char *result, int size) ! { ! WIN32_FIND_DATA fd; ! HANDLE h; ! char *src, *dst, *dend; ! ! src = pathWithCanonicalPrefix; ! dst = result; /* Place results here */ ! dend = dst + size; /* Don't go to or past here */ ! ! h = FindFirstFile(pathWithCanonicalPrefix, &fd); /* Look up file */ ! if (h != INVALID_HANDLE_VALUE) { ! /* Lookup succeeded; concatenate true name to prefix */ ! FindClose(h); ! if (!(dst = cp(dst, dend, '\0', ! canonicalPrefix, ! canonicalPrefix + strlen(canonicalPrefix)))) { ! return -1; ! } ! if (!(dst = cp(dst, dend, '\\', ! fd.cFileName, ! fd.cFileName + strlen(fd.cFileName)))) { ! return -1; ! } ! } else { ! if (!lastErrorReportable()) { ! if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) { ! return -1; ! } ! } else { ! return -1; ! } ! } ! if (dst >= dend) { ! errno = ENAMETOOLONG; ! return -1; ! } ! *dst = '\0'; ! return 0; } - /* Wide character version of canonicalize. Size is a wide-character size. */ int wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) { --- 159,205 ---- have been converted to native form already, via JVM_NativePath(). This is necessary because _fullpath() rejects duplicate separator characters on Win95, though it accepts them on NT. */ int ! canonicalize(char* path, char* result, int size) { ! wchar_t* wpath = NULL; ! wchar_t* wresult = NULL; ! size_t conv; ! size_t path_len = strlen(path); ! int ret = -1; ! if ((wpath = (wchar_t*) malloc(sizeof(wchar_t) * (path_len + 1))) == NULL) { ! goto finish; } ! if (mbstowcs_s(&conv, wpath, path_len + 1, path, path_len) != 0) { ! goto finish; } ! if ((wresult = (wchar_t*) malloc(sizeof(wchar_t) * size)) == NULL) { ! goto finish; } ! if (wcanonicalize(wpath, wresult, size) != 0) { ! goto finish; } ! if (wcstombs_s(&conv, result, (size_t) size, wresult, (size_t) (size - 1)) != 0) { ! goto finish; } ! // Change return value to success. ! ret = 0; ! finish: ! free(wresult); ! free(wpath); ! return ret; } /* Wide character version of canonicalize. Size is a wide-character size. */ int wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) {
< prev index next >