39 #include <errno.h> |
39 #include <errno.h> |
40 #include "io_util_md.h" |
40 #include "io_util_md.h" |
41 |
41 |
42 #undef DEBUG_PATH /* Define this to debug path code */ |
42 #undef DEBUG_PATH /* Define this to debug path code */ |
43 |
43 |
44 #define isfilesep(c) ((c) == '/' || (c) == '\\') |
|
45 #define wisfilesep(c) ((c) == L'/' || (c) == L'\\') |
|
46 #define islb(c) (IsDBCSLeadByte((BYTE)(c))) |
|
47 |
|
48 |
|
49 /* Copy bytes to dst, not going past dend; return dst + number of bytes copied, |
44 /* Copy bytes to dst, not going past dend; return dst + number of bytes copied, |
50 or NULL if dend would have been exceeded. If first != '\0', copy that byte |
45 or NULL if dend would have been exceeded. If first != '\0', copy that byte |
51 before copying bytes from src to send - 1. */ |
46 before copying bytes from src to send - 1. */ |
52 |
|
53 static char * |
|
54 cp(char *dst, char *dend, char first, char *src, char *send) |
|
55 { |
|
56 char *p = src, *q = dst; |
|
57 if (first != '\0') { |
|
58 if (q < dend) { |
|
59 *q++ = first; |
|
60 } else { |
|
61 errno = ENAMETOOLONG; |
|
62 return NULL; |
|
63 } |
|
64 } |
|
65 if (send - p > dend - q) { |
|
66 errno = ENAMETOOLONG; |
|
67 return NULL; |
|
68 } |
|
69 while (p < send) { |
|
70 *q++ = *p++; |
|
71 } |
|
72 return q; |
|
73 } |
|
74 |
|
75 /* Wide character version of cp */ |
|
76 |
|
77 static WCHAR* |
47 static WCHAR* |
78 wcp(WCHAR *dst, WCHAR *dend, WCHAR first, WCHAR *src, WCHAR *send) |
48 wcp(WCHAR *dst, WCHAR *dend, WCHAR first, WCHAR *src, WCHAR *send) |
79 { |
49 { |
80 WCHAR *p = src, *q = dst; |
50 WCHAR *p = src, *q = dst; |
81 if (first != L'\0') { |
51 if (first != L'\0') { |
223 jio_fprintf(stderr, "canonicalize: errval %d\n", errval); |
143 jio_fprintf(stderr, "canonicalize: errval %d\n", errval); |
224 #endif |
144 #endif |
225 return 1; |
145 return 1; |
226 } |
146 } |
227 |
147 |
228 int wcanonicalize(WCHAR *orig_path, WCHAR *result, int size); |
|
229 |
|
230 /* Convert a pathname to canonical form. The input orig_path is assumed to |
148 /* Convert a pathname to canonical form. The input orig_path is assumed to |
231 have been converted to native form already, via JVM_NativePath(). This is |
149 have been converted to native form already, via JVM_NativePath(). This is |
232 necessary because _fullpath() rejects duplicate separator characters on |
150 necessary because _fullpath() rejects duplicate separator characters on |
233 Win95, though it accepts them on NT. */ |
151 Win95, though it accepts them on NT. */ |
234 |
|
235 int |
|
236 canonicalize(char *orig_path, char *result, int size) |
|
237 { |
|
238 WIN32_FIND_DATA fd; |
|
239 HANDLE h; |
|
240 char path[1024]; /* Working copy of path */ |
|
241 char *src, *dst, *dend; |
|
242 wchar_t *worig_path, *wresult; |
|
243 size_t converted_chars = 0; |
|
244 |
|
245 /* handle long path with length >= MAX_PATH */ |
|
246 if (strlen(orig_path) >= MAX_PATH) { |
|
247 if ((worig_path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) |
|
248 return -1; |
|
249 |
|
250 if (mbstowcs_s(&converted_chars, worig_path, (size_t)size, orig_path, (size_t)(size - 1)) != 0) { |
|
251 free(worig_path); |
|
252 return -1; |
|
253 } |
|
254 |
|
255 if ((wresult = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) |
|
256 return -1; |
|
257 |
|
258 if (wcanonicalize(worig_path, wresult, size) != 0) { |
|
259 free(worig_path); |
|
260 free(wresult); |
|
261 return -1; |
|
262 } |
|
263 |
|
264 if (wcstombs_s(&converted_chars, result, (size_t)size, wresult, (size_t)(size - 1)) != 0) { |
|
265 free(worig_path); |
|
266 free(wresult); |
|
267 return -1; |
|
268 } |
|
269 |
|
270 free(worig_path); |
|
271 free(wresult); |
|
272 return 0; |
|
273 } |
|
274 |
|
275 /* Reject paths that contain wildcards */ |
|
276 if (wild(orig_path)) { |
|
277 errno = EINVAL; |
|
278 return -1; |
|
279 } |
|
280 |
|
281 /* Collapse instances of "foo\.." and ensure absoluteness. Note that |
|
282 contrary to the documentation, the _fullpath procedure does not require |
|
283 the drive to be available. It also does not reliably change all |
|
284 occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */ |
|
285 if (!_fullpath(path, orig_path, sizeof(path))) { |
|
286 return -1; |
|
287 } |
|
288 |
|
289 /* Correction for Win95: _fullpath may leave a trailing "\\" |
|
290 on a UNC pathname */ |
|
291 if ((path[0] == '\\') && (path[1] == '\\')) { |
|
292 char *p = path + strlen(path); |
|
293 if ((p[-1] == '\\') && !islb(p[-2])) { |
|
294 p[-1] = '\0'; |
|
295 } |
|
296 } |
|
297 |
|
298 if (dots(path)) /* Check for prohibited combinations of dots */ |
|
299 return -1; |
|
300 |
|
301 src = path; /* Start scanning here */ |
|
302 dst = result; /* Place results here */ |
|
303 dend = dst + size; /* Don't go to or past here */ |
|
304 |
|
305 /* Copy prefix, assuming path is absolute */ |
|
306 if (isalpha(src[0]) && (src[1] == ':') && (src[2] == '\\')) { |
|
307 /* Drive specifier */ |
|
308 *src = toupper(*src); /* Canonicalize drive letter */ |
|
309 if (!(dst = cp(dst, dend, '\0', src, src + 2))) { |
|
310 return -1; |
|
311 } |
|
312 src += 2; |
|
313 } else if ((src[0] == '\\') && (src[1] == '\\')) { |
|
314 /* UNC pathname */ |
|
315 char *p; |
|
316 p = nextsep(src + 2); /* Skip past host name */ |
|
317 if (!*p) { |
|
318 /* A UNC pathname must begin with "\\\\host\\share", |
|
319 so reject this path as invalid if there is no share name */ |
|
320 errno = EINVAL; |
|
321 return -1; |
|
322 } |
|
323 p = nextsep(p + 1); /* Skip past share name */ |
|
324 if (!(dst = cp(dst, dend, '\0', src, p))) { |
|
325 return -1; |
|
326 } |
|
327 src = p; |
|
328 } else { |
|
329 /* Invalid path */ |
|
330 errno = EINVAL; |
|
331 return -1; |
|
332 } |
|
333 |
|
334 /* Windows 95/98/Me bug - FindFirstFile fails on network mounted drives */ |
|
335 /* for root pathes like "E:\" . If the path has this form, we should */ |
|
336 /* simply return it, it is already canonicalized. */ |
|
337 if (strlen(path) == 3 && path[1] == ':' && path[2] == '\\') { |
|
338 /* At this point we have already copied the drive specifier ("z:")*/ |
|
339 /* so we need to copy "\" and the null character. */ |
|
340 result[2] = '\\'; |
|
341 result[3] = '\0'; |
|
342 return 0; |
|
343 } |
|
344 |
|
345 /* At this point we have copied either a drive specifier ("z:") or a UNC |
|
346 prefix ("\\\\host\\share") to the result buffer, and src points to the |
|
347 first byte of the remainder of the path. We now scan through the rest |
|
348 of the path, looking up each prefix in order to find the true name of |
|
349 the last element of each prefix, thereby computing the full true name of |
|
350 the original path. */ |
|
351 while (*src) { |
|
352 char *p = nextsep(src + 1); /* Find next separator */ |
|
353 char c = *p; |
|
354 assert(*src == '\\'); /* Invariant */ |
|
355 *p = '\0'; /* Temporarily clear separator */ |
|
356 h = FindFirstFile(path, &fd); /* Look up prefix */ |
|
357 *p = c; /* Restore separator */ |
|
358 if (h != INVALID_HANDLE_VALUE) { |
|
359 /* Lookup succeeded; append true name to result and continue */ |
|
360 FindClose(h); |
|
361 if (!(dst = cp(dst, dend, '\\', |
|
362 fd.cFileName, |
|
363 fd.cFileName + strlen(fd.cFileName)))) { |
|
364 return -1; |
|
365 } |
|
366 src = p; |
|
367 continue; |
|
368 } else { |
|
369 if (!lastErrorReportable()) { |
|
370 if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) { |
|
371 return -1; |
|
372 } |
|
373 break; |
|
374 } else { |
|
375 return -1; |
|
376 } |
|
377 } |
|
378 } |
|
379 |
|
380 if (dst >= dend) { |
|
381 errno = ENAMETOOLONG; |
|
382 return -1; |
|
383 } |
|
384 *dst = '\0'; |
|
385 return 0; |
|
386 |
|
387 } |
|
388 |
|
389 |
|
390 /* Convert a pathname to canonical form. The input prefix is assumed |
|
391 to be in canonical form already, and the trailing filename must not |
|
392 contain any wildcard, dot/double dot, or other "tricky" characters |
|
393 that are rejected by the canonicalize() routine above. This |
|
394 routine is present to allow the canonicalization prefix cache to be |
|
395 used while still returning canonical names with the correct |
|
396 capitalization. */ |
|
397 |
|
398 int |
|
399 canonicalizeWithPrefix(char* canonicalPrefix, char* pathWithCanonicalPrefix, char *result, int size) |
|
400 { |
|
401 WIN32_FIND_DATA fd; |
|
402 HANDLE h; |
|
403 char *src, *dst, *dend; |
|
404 |
|
405 src = pathWithCanonicalPrefix; |
|
406 dst = result; /* Place results here */ |
|
407 dend = dst + size; /* Don't go to or past here */ |
|
408 |
|
409 h = FindFirstFile(pathWithCanonicalPrefix, &fd); /* Look up file */ |
|
410 if (h != INVALID_HANDLE_VALUE) { |
|
411 /* Lookup succeeded; concatenate true name to prefix */ |
|
412 FindClose(h); |
|
413 if (!(dst = cp(dst, dend, '\0', |
|
414 canonicalPrefix, |
|
415 canonicalPrefix + strlen(canonicalPrefix)))) { |
|
416 return -1; |
|
417 } |
|
418 if (!(dst = cp(dst, dend, '\\', |
|
419 fd.cFileName, |
|
420 fd.cFileName + strlen(fd.cFileName)))) { |
|
421 return -1; |
|
422 } |
|
423 } else { |
|
424 if (!lastErrorReportable()) { |
|
425 if (!(dst = cp(dst, dend, '\0', src, src + strlen(src)))) { |
|
426 return -1; |
|
427 } |
|
428 } else { |
|
429 return -1; |
|
430 } |
|
431 } |
|
432 |
|
433 if (dst >= dend) { |
|
434 errno = ENAMETOOLONG; |
|
435 return -1; |
|
436 } |
|
437 *dst = '\0'; |
|
438 return 0; |
|
439 } |
|
440 |
|
441 |
|
442 /* Wide character version of canonicalize. Size is a wide-character size. */ |
|
443 |
|
444 int |
152 int |
445 wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) |
153 wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) |
446 { |
154 { |
447 WIN32_FIND_DATAW fd; |
155 WIN32_FIND_DATAW fd; |
448 HANDLE h; |
156 HANDLE h; |