annotate src/windows/native/java/io/canonicalize_md.c @ 3909:272483f6650b

7033660: Update copyright year to 2011 on any files changed in 2011 Reviewed-by: dholmes
author ohair
date Wed, 06 Apr 2011 22:06:11 -0700
parents f9f321a7502c
children
rev   line source
duke@0 1 /*
ohair@3909 2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 /*
duke@0 27 * Pathname canonicalization for Win32 file systems
duke@0 28 */
duke@0 29
duke@0 30 #include <stdio.h>
duke@0 31 #include <stdlib.h>
duke@0 32 #include <string.h>
duke@0 33 #include <ctype.h>
duke@0 34 #include <assert.h>
duke@0 35 #include <sys/stat.h>
duke@0 36
duke@0 37 #include <windows.h>
duke@0 38 #include <winbase.h>
duke@0 39 #include <errno.h>
duke@0 40 #include "io_util_md.h"
duke@0 41
duke@0 42 #undef DEBUG_PATH /* Define this to debug path code */
duke@0 43
duke@0 44 #define isfilesep(c) ((c) == '/' || (c) == '\\')
duke@0 45 #define wisfilesep(c) ((c) == L'/' || (c) == L'\\')
duke@0 46 #define islb(c) (IsDBCSLeadByte((BYTE)(c)))
duke@0 47
duke@0 48
duke@0 49 /* Copy bytes to dst, not going past dend; return dst + number of bytes copied,
duke@0 50 or NULL if dend would have been exceeded. If first != '\0', copy that byte
duke@0 51 before copying bytes from src to send - 1. */
duke@0 52
duke@0 53 static char *
duke@0 54 cp(char *dst, char *dend, char first, char *src, char *send)
duke@0 55 {
duke@0 56 char *p = src, *q = dst;
duke@0 57 if (first != '\0') {
duke@0 58 if (q < dend) {
duke@0 59 *q++ = first;
duke@0 60 } else {
duke@0 61 errno = ENAMETOOLONG;
duke@0 62 return NULL;
duke@0 63 }
duke@0 64 }
duke@0 65 if (send - p > dend - q) {
duke@0 66 errno = ENAMETOOLONG;
duke@0 67 return NULL;
duke@0 68 }
duke@0 69 while (p < send) {
duke@0 70 *q++ = *p++;
duke@0 71 }
duke@0 72 return q;
duke@0 73 }
duke@0 74
duke@0 75 /* Wide character version of cp */
duke@0 76
duke@0 77 static WCHAR*
duke@0 78 wcp(WCHAR *dst, WCHAR *dend, WCHAR first, WCHAR *src, WCHAR *send)
duke@0 79 {
duke@0 80 WCHAR *p = src, *q = dst;
duke@0 81 if (first != L'\0') {
duke@0 82 if (q < dend) {
duke@0 83 *q++ = first;
duke@0 84 } else {
duke@0 85 errno = ENAMETOOLONG;
duke@0 86 return NULL;
duke@0 87 }
duke@0 88 }
duke@0 89 if (send - p > dend - q) {
duke@0 90 errno = ENAMETOOLONG;
duke@0 91 return NULL;
duke@0 92 }
duke@0 93 while (p < send)
duke@0 94 *q++ = *p++;
duke@0 95 return q;
duke@0 96 }
duke@0 97
duke@0 98
duke@0 99 /* Find first instance of '\\' at or following start. Return the address of
duke@0 100 that byte or the address of the null terminator if '\\' is not found. */
duke@0 101
duke@0 102 static char *
duke@0 103 nextsep(char *start)
duke@0 104 {
duke@0 105 char *p = start;
duke@0 106 int c;
duke@0 107 while ((c = *p) && (c != '\\')) {
duke@0 108 p += ((islb(c) && p[1]) ? 2 : 1);
duke@0 109 }
duke@0 110 return p;
duke@0 111 }
duke@0 112
duke@0 113 /* Wide character version of nextsep */
duke@0 114
duke@0 115 static WCHAR *
duke@0 116 wnextsep(WCHAR *start)
duke@0 117 {
duke@0 118 WCHAR *p = start;
duke@0 119 int c;
duke@0 120 while ((c = *p) && (c != L'\\'))
duke@0 121 p++;
duke@0 122 return p;
duke@0 123 }
duke@0 124
duke@0 125 /* Tell whether the given string contains any wildcard characters */
duke@0 126
duke@0 127 static int
duke@0 128 wild(char *start)
duke@0 129 {
duke@0 130 char *p = start;
duke@0 131 int c;
duke@0 132 while (c = *p) {
duke@0 133 if ((c == '*') || (c == '?')) return 1;
duke@0 134 p += ((islb(c) && p[1]) ? 2 : 1);
duke@0 135 }
duke@0 136 return 0;
duke@0 137 }
duke@0 138
duke@0 139 /* Wide character version of wild */
duke@0 140
duke@0 141 static int
duke@0 142 wwild(WCHAR *start)
duke@0 143 {
duke@0 144 WCHAR *p = start;
duke@0 145 int c;
duke@0 146 while (c = *p) {
duke@0 147 if ((c == L'*') || (c == L'?'))
duke@0 148 return 1;
duke@0 149 p++;
duke@0 150 }
duke@0 151 return 0;
duke@0 152 }
duke@0 153
duke@0 154 /* Tell whether the given string contains prohibited combinations of dots.
duke@0 155 In the canonicalized form no path element may have dots at its end.
duke@0 156 Allowed canonical paths: c:\xa...dksd\..ksa\.lk c:\...a\.b\cd..x.x
duke@0 157 Prohibited canonical paths: c:\..\x c:\x.\d c:\...
duke@0 158 */
duke@0 159 static int
duke@0 160 dots(char *start)
duke@0 161 {
duke@0 162 char *p = start;
duke@0 163 while (*p) {
duke@0 164 if ((p = strchr(p, '.')) == NULL) // find next occurence of '.'
duke@0 165 return 0; // no more dots
duke@0 166 p++; // next char
duke@0 167 while ((*p) == '.') // go to the end of dots
duke@0 168 p++;
duke@0 169 if (*p && (*p != '\\')) // path element does not end with a dot
duke@0 170 p++; // go to the next char
duke@0 171 else
duke@0 172 return 1; // path element does end with a dot - prohibited
duke@0 173 }
duke@0 174 return 0; // no prohibited combinations of dots found
duke@0 175 }
duke@0 176
duke@0 177 /* Wide character version of dots */
duke@0 178 static int
duke@0 179 wdots(WCHAR *start)
duke@0 180 {
duke@0 181 WCHAR *p = start;
duke@0 182 while (*p) {
duke@0 183 if ((p = wcschr(p, L'.')) == NULL) // find next occurence of '.'
duke@0 184 return 0; // no more dots
duke@0 185 p++; // next char
duke@0 186 while ((*p) == L'.') // go to the end of dots
duke@0 187 p++;
duke@0 188 if (*p && (*p != L'\\')) // path element does not end with a dot
duke@0 189 p++; // go to the next char
duke@0 190 else
duke@0 191 return 1; // path element does end with a dot - prohibited
duke@0 192 }
duke@0 193 return 0; // no prohibited combinations of dots found
duke@0 194 }
duke@0 195
duke@0 196 /* If the lookup of a particular prefix fails because the file does not exist,
duke@0 197 because it is of the wrong type, because access is denied, or because the
duke@0 198 network is unreachable then canonicalization does not fail, it terminates
duke@0 199 successfully after copying the rest of the original path to the result path.
duke@0 200 Other I/O errors cause an error return.
duke@0 201 */
duke@0 202
duke@0 203 int
duke@0 204 lastErrorReportable()
duke@0 205 {
duke@0 206 DWORD errval = GetLastError();
duke@0 207 if ((errval == ERROR_FILE_NOT_FOUND)
duke@0 208 || (errval == ERROR_DIRECTORY)
duke@0 209 || (errval == ERROR_PATH_NOT_FOUND)
duke@0 210 || (errval == ERROR_BAD_NETPATH)
duke@0 211 || (errval == ERROR_BAD_NET_NAME)
duke@0 212 || (errval == ERROR_ACCESS_DENIED)
duke@0 213 || (errval == ERROR_NETWORK_UNREACHABLE)
duke@0 214 || (errval == ERROR_NETWORK_ACCESS_DENIED)) {
duke@0 215 return 0;
duke@0 216 }
duke@0 217
duke@0 218 #ifdef DEBUG_PATH
duke@0 219 jio_fprintf(stderr, "canonicalize: errval %d\n", errval);
duke@0 220 #endif
duke@0 221 return 1;
duke@0 222 }
duke@0 223
duke@0 224 /* Convert a pathname to canonical form. The input orig_path is assumed to
duke@0 225 have been converted to native form already, via JVM_NativePath(). This is
duke@0 226 necessary because _fullpath() rejects duplicate separator characters on
duke@0 227 Win95, though it accepts them on NT. */
duke@0 228
duke@0 229 int
duke@0 230 canonicalize(char *orig_path, char *result, int size)
duke@0 231 {
duke@0 232 WIN32_FIND_DATA fd;
duke@0 233 HANDLE h;
duke@0 234 char path[1024]; /* Working copy of path */
duke@0 235 char *src, *dst, *dend;
duke@0 236
duke@0 237 /* Reject paths that contain wildcards */
duke@0 238 if (wild(orig_path)) {
duke@0 239 errno = EINVAL;
duke@0 240 return -1;
duke@0 241 }
duke@0 242
duke@0 243 /* Collapse instances of "foo\.." and ensure absoluteness. Note that
duke@0 244 contrary to the documentation, the _fullpath procedure does not require
duke@0 245 the drive to be available. It also does not reliably change all
duke@0 246 occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */
duke@0 247 if(!_fullpath(path, orig_path, sizeof(path))) {
duke@0 248 return -1;
duke@0 249 }
duke@0 250
duke@0 251 /* Correction for Win95: _fullpath may leave a trailing "\\"
duke@0 252 on a UNC pathname */
duke@0 253 if ((path[0] == '\\') && (path[1] == '\\')) {
duke@0 254 char *p = path + strlen(path);
duke@0 255 if ((p[-1] == '\\') && !islb(p[-2])) {
duke@0 256 p[-1] = '\0';
duke@0 257 }
duke@0 258 }
duke@0 259
duke@0 260 if (dots(path)) /* Check for prohibited combinations of dots */
duke@0 261 return -1;
duke@0 262
duke@0 263 src = path; /* Start scanning here */
duke@0 264 dst = result; /* Place results here */
duke@0 265 dend = dst + size; /* Don't go to or past here */
duke@0 266
duke@0 267 /* Copy prefix, assuming path is absolute */
duke@0 268 if (isalpha(src[0]) && (src[1] == ':') && (src[2] == '\\')) {
duke@0 269 /* Drive specifier */
duke@0 270 *src = toupper(*src); /* Canonicalize drive letter */
duke@0 271 if (!(dst = cp(dst, dend, '\0', src, src + 2))) {
duke@0 272 return -1;
duke@0 273 }
duke@0 274 src += 2;
duke@0 275 } else if ((src[0] == '\\') && (src[1] == '\\')) {
duke@0 276 /* UNC pathname */
duke@0 277 char *p;
duke@0 278 p = nextsep(src + 2); /* Skip past host name */
duke@0 279 if (!*p) {
duke@0 280 /* A UNC pathname must begin with "\\\\host\\share",
duke@0 281 so reject this path as invalid if there is no share name */
duke@0 282 errno = EINVAL;
duke@0 283 return -1;
duke@0 284 }
duke@0 285 p = nextsep(p + 1); /* Skip past share name */
duke@0 286 if (!(dst = cp(dst, dend, '\0', src, p))) {
duke@0 287 return -1;
duke@0 288 }
duke@0 289 src = p;
duke@0 290 } else {
duke@0 291 /* Invalid path */
duke@0 292 errno = EINVAL;
duke@0 293 return -1;
duke@0 294 }
duke@0 295
duke@0 296 /* Windows 95/98/Me bug - FindFirstFile fails on network mounted drives */
duke@0 297 /* for root pathes like "E:\" . If the path has this form, we should */
duke@0 298 /* simply return it, it is already canonicalized. */
duke@0 299 if (strlen(path) == 3 && path[1] == ':' && path[2] == '\\') {
duke@0 300 /* At this point we have already copied the drive specifier ("z:")*/
duke@0 301 /* so we need to copy "\" and the null character. */
duke@0 302 result[2] = '\\';
duke@0 303 result[3] = '\0';
duke@0 304 return 0;
duke@0 305 }
duke@0 306
duke@0 307 /* At this point we have copied either a drive specifier ("z:") or a UNC
duke@0 308 prefix ("\\\\host\\share") to the result buffer, and src points to the
duke@0 309 first byte of the remainder of the path. We now scan through the rest
duke@0 310 of the path, looking up each prefix in order to find the true name of
duke@0 311 the last element of each prefix, thereby computing the full true name of
duke@0 312 the original path. */
duke@0 313 while (*src) {
duke@0 314 char *p = nextsep(src + 1); /* Find next separator */
duke@0 315 char c = *p;
duke@0 316 assert(*src == '\\'); /* Invariant */
duke@0 317 *p = '\0'; /* Temporarily clear separator */
duke@0 318 h = FindFirstFile(path, &fd); /* Look up prefix */
duke@0 319 *p = c; /* Restore separator */
duke@0 320 if (h != INVALID_HANDLE_VALUE) {
duke@0 321 /* Lookup succeeded; append true name to result and continue */
duke@0 322 FindClose(h);
duke@0 323 if (!(dst = cp(dst, dend, '\\',
duke@0 324 fd.cFileName,
duke@0 325 fd.cFileName + strlen(fd.cFileName)))) {
duke@0 326 return -1;
duke@0 327 }
duke@0 328 src = p;
duke@0 329 continue;
duke@0 330 } else {
duke@0 331 if (!lastErrorReportable()) {
duke@0 332 if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) {
duke@0 333 return -1;
duke@0 334 }
duke@0 335 break;
duke@0 336 } else {
duke@0 337 return -1;
duke@0 338 }
duke@0 339 }
duke@0 340 }
duke@0 341
duke@0 342 if (dst >= dend) {
duke@0 343 errno = ENAMETOOLONG;
duke@0 344 return -1;
duke@0 345 }
duke@0 346 *dst = '\0';
duke@0 347 return 0;
duke@0 348
duke@0 349 }
duke@0 350
duke@0 351
duke@0 352 /* Convert a pathname to canonical form. The input prefix is assumed
duke@0 353 to be in canonical form already, and the trailing filename must not
duke@0 354 contain any wildcard, dot/double dot, or other "tricky" characters
duke@0 355 that are rejected by the canonicalize() routine above. This
duke@0 356 routine is present to allow the canonicalization prefix cache to be
duke@0 357 used while still returning canonical names with the correct
duke@0 358 capitalization. */
duke@0 359
duke@0 360 int
duke@0 361 canonicalizeWithPrefix(char* canonicalPrefix, char* pathWithCanonicalPrefix, char *result, int size)
duke@0 362 {
duke@0 363 WIN32_FIND_DATA fd;
duke@0 364 HANDLE h;
duke@0 365 char *src, *dst, *dend;
duke@0 366
duke@0 367 src = pathWithCanonicalPrefix;
duke@0 368 dst = result; /* Place results here */
duke@0 369 dend = dst + size; /* Don't go to or past here */
duke@0 370
duke@0 371 h = FindFirstFile(pathWithCanonicalPrefix, &fd); /* Look up file */
duke@0 372 if (h != INVALID_HANDLE_VALUE) {
duke@0 373 /* Lookup succeeded; concatenate true name to prefix */
duke@0 374 FindClose(h);
duke@0 375 if (!(dst = cp(dst, dend, '\0',
duke@0 376 canonicalPrefix,
duke@0 377 canonicalPrefix + strlen(canonicalPrefix)))) {
duke@0 378 return -1;
duke@0 379 }
duke@0 380 if (!(dst = cp(dst, dend, '\\',
duke@0 381 fd.cFileName,
duke@0 382 fd.cFileName + strlen(fd.cFileName)))) {
duke@0 383 return -1;
duke@0 384 }
duke@0 385 } else {
duke@0 386 if (!lastErrorReportable()) {
duke@0 387 if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) {
duke@0 388 return -1;
duke@0 389 }
duke@0 390 } else {
duke@0 391 return -1;
duke@0 392 }
duke@0 393 }
duke@0 394
duke@0 395 if (dst >= dend) {
duke@0 396 errno = ENAMETOOLONG;
duke@0 397 return -1;
duke@0 398 }
duke@0 399 *dst = '\0';
duke@0 400 return 0;
duke@0 401 }
duke@0 402
duke@0 403
duke@0 404 /* Wide character version of canonicalize. Size is a wide-character size. */
duke@0 405
duke@0 406 int
duke@0 407 wcanonicalize(WCHAR *orig_path, WCHAR *result, int size)
duke@0 408 {
duke@0 409 WIN32_FIND_DATAW fd;
duke@0 410 HANDLE h;
duke@0 411 WCHAR *path; /* Working copy of path */
duke@0 412 WCHAR *src, *dst, *dend, c;
duke@0 413
duke@0 414 /* Reject paths that contain wildcards */
duke@0 415 if (wwild(orig_path)) {
duke@0 416 errno = EINVAL;
duke@0 417 return -1;
duke@0 418 }
duke@0 419
duke@0 420 if ((path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL)
duke@0 421 return -1;
duke@0 422
duke@0 423 /* Collapse instances of "foo\.." and ensure absoluteness. Note that
duke@0 424 contrary to the documentation, the _fullpath procedure does not require
duke@0 425 the drive to be available. */
duke@0 426 if(!_wfullpath(path, orig_path, size)) {
duke@0 427 goto err;
duke@0 428 }
duke@0 429
duke@0 430 if (wdots(path)) /* Check for prohibited combinations of dots */
duke@0 431 goto err;
duke@0 432
duke@0 433 src = path; /* Start scanning here */
duke@0 434 dst = result; /* Place results here */
duke@0 435 dend = dst + size; /* Don't go to or past here */
duke@0 436
duke@0 437 /* Copy prefix, assuming path is absolute */
duke@0 438 c = src[0];
duke@0 439 if (((c <= L'z' && c >= L'a') || (c <= L'Z' && c >= L'A'))
duke@0 440 && (src[1] == L':') && (src[2] == L'\\')) {
duke@0 441 /* Drive specifier */
duke@0 442 *src = towupper(*src); /* Canonicalize drive letter */
duke@0 443 if (!(dst = wcp(dst, dend, L'\0', src, src + 2))) {
duke@0 444 goto err;
duke@0 445 }
duke@0 446
duke@0 447 src += 2;
duke@0 448 } else if ((src[0] == L'\\') && (src[1] == L'\\')) {
duke@0 449 /* UNC pathname */
duke@0 450 WCHAR *p;
duke@0 451 p = wnextsep(src + 2); /* Skip past host name */
duke@0 452 if (!*p) {
duke@0 453 /* A UNC pathname must begin with "\\\\host\\share",
duke@0 454 so reject this path as invalid if there is no share name */
duke@0 455 errno = EINVAL;
duke@0 456 goto err;
duke@0 457 }
duke@0 458 p = wnextsep(p + 1); /* Skip past share name */
duke@0 459 if (!(dst = wcp(dst, dend, L'\0', src, p)))
duke@0 460 goto err;
duke@0 461 src = p;
duke@0 462 } else {
duke@0 463 /* Invalid path */
duke@0 464 errno = EINVAL;
duke@0 465 goto err;
duke@0 466 }
duke@0 467 /* At this point we have copied either a drive specifier ("z:") or a UNC
duke@0 468 prefix ("\\\\host\\share") to the result buffer, and src points to the
duke@0 469 first byte of the remainder of the path. We now scan through the rest
duke@0 470 of the path, looking up each prefix in order to find the true name of
duke@0 471 the last element of each prefix, thereby computing the full true name of
duke@0 472 the original path. */
duke@0 473 while (*src) {
duke@0 474 WCHAR *p = wnextsep(src + 1); /* Find next separator */
duke@0 475 WCHAR c = *p;
duke@0 476 WCHAR *pathbuf;
duke@0 477 int pathlen;
duke@0 478
duke@0 479 assert(*src == L'\\'); /* Invariant */
duke@0 480 *p = L'\0'; /* Temporarily clear separator */
duke@0 481
alanb@3499 482 if ((pathlen = (int)wcslen(path)) > MAX_PATH - 1) {
duke@0 483 pathbuf = getPrefixed(path, pathlen);
duke@0 484 h = FindFirstFileW(pathbuf, &fd); /* Look up prefix */
duke@0 485 free(pathbuf);
duke@0 486 } else
duke@0 487 h = FindFirstFileW(path, &fd); /* Look up prefix */
duke@0 488
duke@0 489 *p = c; /* Restore separator */
duke@0 490 if (h != INVALID_HANDLE_VALUE) {
duke@0 491 /* Lookup succeeded; append true name to result and continue */
duke@0 492 FindClose(h);
duke@0 493 if (!(dst = wcp(dst, dend, L'\\', fd.cFileName,
duke@0 494 fd.cFileName + wcslen(fd.cFileName)))){
duke@0 495 goto err;
duke@0 496 }
duke@0 497 src = p;
duke@0 498 continue;
duke@0 499 } else {
duke@0 500 if (!lastErrorReportable()) {
duke@0 501 if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){
duke@0 502 goto err;
duke@0 503 }
duke@0 504 break;
duke@0 505 } else {
duke@0 506 goto err;
duke@0 507 }
duke@0 508 }
duke@0 509 }
duke@0 510
duke@0 511 if (dst >= dend) {
duke@0 512 errno = ENAMETOOLONG;
duke@0 513 goto err;
duke@0 514 }
duke@0 515 *dst = L'\0';
duke@0 516 free(path);
duke@0 517 return 0;
duke@0 518
duke@0 519 err:
duke@0 520 free(path);
duke@0 521 return -1;
duke@0 522 }
duke@0 523
duke@0 524
duke@0 525 /* Wide character version of canonicalizeWithPrefix. */
duke@0 526
duke@0 527 int
duke@0 528 wcanonicalizeWithPrefix(WCHAR *canonicalPrefix, WCHAR *pathWithCanonicalPrefix, WCHAR *result, int size)
duke@0 529 {
duke@0 530 WIN32_FIND_DATAW fd;
duke@0 531 HANDLE h;
duke@0 532 WCHAR *src, *dst, *dend;
duke@0 533 WCHAR *pathbuf;
duke@0 534 int pathlen;
duke@0 535
duke@0 536 src = pathWithCanonicalPrefix;
duke@0 537 dst = result; /* Place results here */
duke@0 538 dend = dst + size; /* Don't go to or past here */
duke@0 539
duke@0 540
alanb@3499 541 if ((pathlen=(int)wcslen(pathWithCanonicalPrefix)) > MAX_PATH - 1) {
duke@0 542 pathbuf = getPrefixed(pathWithCanonicalPrefix, pathlen);
duke@0 543 h = FindFirstFileW(pathbuf, &fd); /* Look up prefix */
duke@0 544 free(pathbuf);
duke@0 545 } else
duke@0 546 h = FindFirstFileW(pathWithCanonicalPrefix, &fd); /* Look up prefix */
duke@0 547 if (h != INVALID_HANDLE_VALUE) {
duke@0 548 /* Lookup succeeded; append true name to result and continue */
duke@0 549 FindClose(h);
duke@0 550 if (!(dst = wcp(dst, dend, L'\0',
duke@0 551 canonicalPrefix,
duke@0 552 canonicalPrefix + wcslen(canonicalPrefix)))) {
duke@0 553 return -1;
duke@0 554 }
duke@0 555 if (!(dst = wcp(dst, dend, L'\\',
duke@0 556 fd.cFileName,
duke@0 557 fd.cFileName + wcslen(fd.cFileName)))) {
duke@0 558 return -1;
duke@0 559 }
duke@0 560 } else {
duke@0 561 if (!lastErrorReportable()) {
duke@0 562 if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))) {
duke@0 563 return -1;
duke@0 564 }
duke@0 565 } else {
duke@0 566 return -1;
duke@0 567 }
duke@0 568 }
duke@0 569
duke@0 570 if (dst >= dend) {
duke@0 571 errno = ENAMETOOLONG;
duke@0 572 return -1;
duke@0 573 }
duke@0 574 *dst = L'\0';
duke@0 575 return 0;
duke@0 576 }
duke@0 577
duke@0 578
duke@0 579 /* The appropriate location of getPrefixed() should be io_util_md.c, but
duke@0 580 java.lang.instrument package has hardwired canonicalize_md.c into their
duke@0 581 dll, to avoid complicate solution such as including io_util_md.c into
duke@0 582 that package, as a workaround we put this method here.
duke@0 583 */
duke@0 584
duke@0 585 /* copy \\?\ or \\?\UNC\ to the front of path*/
duke@0 586 WCHAR*
duke@0 587 getPrefixed(const WCHAR* path, int pathlen) {
duke@0 588 WCHAR* pathbuf = (WCHAR*)malloc((pathlen + 10) * sizeof (WCHAR));
duke@0 589 if (pathbuf != 0) {
duke@0 590 if (path[0] == L'\\' && path[1] == L'\\') {
duke@0 591 if (path[2] == L'?' && path[3] == L'\\'){
duke@0 592 /* if it already has a \\?\ don't do the prefix */
duke@0 593 wcscpy(pathbuf, path );
duke@0 594 } else {
duke@0 595 /* only UNC pathname includes double slashes here */
duke@0 596 wcscpy(pathbuf, L"\\\\?\\UNC\0");
duke@0 597 wcscat(pathbuf, path + 1);
duke@0 598 }
duke@0 599 } else {
duke@0 600 wcscpy(pathbuf, L"\\\\?\\\0");
duke@0 601 wcscat(pathbuf, path );
duke@0 602 }
duke@0 603 }
duke@0 604 return pathbuf;
duke@0 605 }