diff options
| author | Eli Zaretskii | 2012-12-24 18:15:13 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2012-12-24 18:15:13 +0200 |
| commit | f5c81c80c109fcaca04b25e08c34848110e2550b (patch) | |
| tree | ab61da6d934e63e361fb1a4915a59325ee95ac9c /src | |
| parent | 216ed9cc435743a596b04917605d29f5ea562e7e (diff) | |
| download | emacs-f5c81c80c109fcaca04b25e08c34848110e2550b.tar.gz emacs-f5c81c80c109fcaca04b25e08c34848110e2550b.zip | |
Fix bug #13262 with crashes in completion on MS-Windows with non-ASCII filenames.
src/fileio.c (file_name_as_directory, directory_file_name): Accept
an additional argument MULTIBYTE to indicate whether the input C
came from a multibyte or a unibyte Lisp string; all callers
adjusted. Don't assume the input string is always multibyte.
(Ffile_name_directory) [DOS_NT]: Handle unibyte strings correctly:
don't ENCODE_FILE them, and return a unibyte string if the input
was unibyte.
(Fexpand_file_name): Don't mix unibyte with multibyte strings, and
don't assume the input strings will always be multibyte. If the
input strings are multibyte, decode strings obtained from C
library functions.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 15 | ||||
| -rw-r--r-- | src/fileio.c | 156 |
2 files changed, 124 insertions, 47 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index e8d5449a99e..c8cc486a9de 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | 2012-12-24 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * fileio.c (file_name_as_directory, directory_file_name): Accept | ||
| 4 | an additional argument MULTIBYTE to indicate whether the input C | ||
| 5 | came from a multibyte or a unibyte Lisp string; all callers | ||
| 6 | adjusted. Don't assume the input string is always multibyte. | ||
| 7 | (Bug#13262) | ||
| 8 | (Ffile_name_directory) [DOS_NT]: Handle unibyte strings correctly: | ||
| 9 | don't ENCODE_FILE them, and return a unibyte string if the input | ||
| 10 | was unibyte. | ||
| 11 | (Fexpand_file_name): Don't mix unibyte with multibyte strings, and | ||
| 12 | don't assume the input strings will always be multibyte. If the | ||
| 13 | input strings are multibyte, decode strings obtained from C | ||
| 14 | library functions. | ||
| 15 | |||
| 1 | 2012-12-22 Martin Rudalics <rudalics@gmx.at> | 16 | 2012-12-22 Martin Rudalics <rudalics@gmx.at> |
| 2 | 17 | ||
| 3 | * window.c (Fselect_window): Reword doc-string (Bug#13248). | 18 | * window.c (Fselect_window): Reword doc-string (Bug#13248). |
diff --git a/src/fileio.c b/src/fileio.c index b0c319cfa62..2d72583e506 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -373,12 +373,26 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 373 | strcat (res, "/"); | 373 | strcat (res, "/"); |
| 374 | beg = res; | 374 | beg = res; |
| 375 | p = beg + strlen (beg); | 375 | p = beg + strlen (beg); |
| 376 | dostounix_filename (beg); | ||
| 377 | tem_fn = make_specified_string (beg, -1, p - beg, | ||
| 378 | STRING_MULTIBYTE (filename)); | ||
| 376 | } | 379 | } |
| 380 | else | ||
| 381 | tem_fn = make_specified_string (beg - 2, -1, p - beg + 2, | ||
| 382 | STRING_MULTIBYTE (filename)); | ||
| 383 | } | ||
| 384 | else if (STRING_MULTIBYTE (filename)) | ||
| 385 | { | ||
| 386 | tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg, 1)); | ||
| 387 | dostounix_filename (SSDATA (tem_fn)); | ||
| 388 | tem_fn = DECODE_FILE (tem_fn); | ||
| 389 | } | ||
| 390 | else | ||
| 391 | { | ||
| 392 | dostounix_filename (beg); | ||
| 393 | tem_fn = make_specified_string (beg, -1, p - beg, 0); | ||
| 377 | } | 394 | } |
| 378 | tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg, | 395 | return tem_fn; |
| 379 | STRING_MULTIBYTE (filename))); | ||
| 380 | dostounix_filename (SSDATA (tem_fn)); | ||
| 381 | return DECODE_FILE (tem_fn); | ||
| 382 | #else /* DOS_NT */ | 396 | #else /* DOS_NT */ |
| 383 | return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename)); | 397 | return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename)); |
| 384 | #endif /* DOS_NT */ | 398 | #endif /* DOS_NT */ |
| @@ -453,12 +467,14 @@ get a current directory to run processes in. */) | |||
| 453 | return Ffile_name_directory (filename); | 467 | return Ffile_name_directory (filename); |
| 454 | } | 468 | } |
| 455 | 469 | ||
| 456 | /* Convert from file name SRC of length SRCLEN to directory name | 470 | /* Convert from file name SRC of length SRCLEN to directory name in |
| 457 | in DST. On UNIX, just make sure there is a terminating /. | 471 | DST. MULTIBYTE non-zero means the file name in SRC is a multibyte |
| 458 | Return the length of DST in bytes. */ | 472 | string. On UNIX, just make sure there is a terminating /. Return |
| 473 | the length of DST in bytes. */ | ||
| 459 | 474 | ||
| 460 | static ptrdiff_t | 475 | static ptrdiff_t |
| 461 | file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen) | 476 | file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen, |
| 477 | bool multibyte) | ||
| 462 | { | 478 | { |
| 463 | if (srclen == 0) | 479 | if (srclen == 0) |
| 464 | { | 480 | { |
| @@ -477,14 +493,17 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen) | |||
| 477 | srclen++; | 493 | srclen++; |
| 478 | } | 494 | } |
| 479 | #ifdef DOS_NT | 495 | #ifdef DOS_NT |
| 480 | { | 496 | if (multibyte) |
| 481 | Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); | 497 | { |
| 498 | Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); | ||
| 482 | 499 | ||
| 483 | tem_fn = ENCODE_FILE (tem_fn); | 500 | tem_fn = ENCODE_FILE (tem_fn); |
| 484 | dostounix_filename (SSDATA (tem_fn)); | 501 | dostounix_filename (SSDATA (tem_fn)); |
| 485 | tem_fn = DECODE_FILE (tem_fn); | 502 | tem_fn = DECODE_FILE (tem_fn); |
| 486 | memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); | 503 | memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); |
| 487 | } | 504 | } |
| 505 | else | ||
| 506 | dostounix_filename (dst); | ||
| 488 | #endif | 507 | #endif |
| 489 | return srclen; | 508 | return srclen; |
| 490 | } | 509 | } |
| @@ -520,16 +539,18 @@ For a Unix-syntax file name, just appends a slash. */) | |||
| 520 | } | 539 | } |
| 521 | 540 | ||
| 522 | buf = alloca (SBYTES (file) + 10); | 541 | buf = alloca (SBYTES (file) + 10); |
| 523 | length = file_name_as_directory (buf, SSDATA (file), SBYTES (file)); | 542 | length = file_name_as_directory (buf, SSDATA (file), SBYTES (file), |
| 543 | STRING_MULTIBYTE (file)); | ||
| 524 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file)); | 544 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file)); |
| 525 | } | 545 | } |
| 526 | 546 | ||
| 527 | /* Convert from directory name SRC of length SRCLEN to | 547 | /* Convert from directory name SRC of length SRCLEN to file name in |
| 528 | file name in DST. On UNIX, just make sure there isn't | 548 | DST. MULTIBYTE non-zero means the file name in SRC is a multibyte |
| 529 | a terminating /. Return the length of DST in bytes. */ | 549 | string. On UNIX, just make sure there isn't a terminating /. |
| 550 | Return the length of DST in bytes. */ | ||
| 530 | 551 | ||
| 531 | static ptrdiff_t | 552 | static ptrdiff_t |
| 532 | directory_file_name (char *dst, char *src, ptrdiff_t srclen) | 553 | directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte) |
| 533 | { | 554 | { |
| 534 | /* Process as Unix format: just remove any final slash. | 555 | /* Process as Unix format: just remove any final slash. |
| 535 | But leave "/" unchanged; do not change it to "". */ | 556 | But leave "/" unchanged; do not change it to "". */ |
| @@ -545,14 +566,17 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen) | |||
| 545 | srclen--; | 566 | srclen--; |
| 546 | } | 567 | } |
| 547 | #ifdef DOS_NT | 568 | #ifdef DOS_NT |
| 548 | { | 569 | if (multibyte) |
| 549 | Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); | 570 | { |
| 571 | Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1); | ||
| 550 | 572 | ||
| 551 | tem_fn = ENCODE_FILE (tem_fn); | 573 | tem_fn = ENCODE_FILE (tem_fn); |
| 552 | dostounix_filename (SSDATA (tem_fn)); | 574 | dostounix_filename (SSDATA (tem_fn)); |
| 553 | tem_fn = DECODE_FILE (tem_fn); | 575 | tem_fn = DECODE_FILE (tem_fn); |
| 554 | memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); | 576 | memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1); |
| 555 | } | 577 | } |
| 578 | else | ||
| 579 | dostounix_filename (dst); | ||
| 556 | #endif | 580 | #endif |
| 557 | return srclen; | 581 | return srclen; |
| 558 | } | 582 | } |
| @@ -588,7 +612,8 @@ In Unix-syntax, this function just removes the final slash. */) | |||
| 588 | } | 612 | } |
| 589 | 613 | ||
| 590 | buf = alloca (SBYTES (directory) + 20); | 614 | buf = alloca (SBYTES (directory) + 20); |
| 591 | length = directory_file_name (buf, SSDATA (directory), SBYTES (directory)); | 615 | length = directory_file_name (buf, SSDATA (directory), SBYTES (directory), |
| 616 | STRING_MULTIBYTE (directory)); | ||
| 592 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory)); | 617 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory)); |
| 593 | } | 618 | } |
| 594 | 619 | ||
| @@ -1038,7 +1063,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1038 | /* `egetenv' may return a unibyte string, which will bite us since | 1063 | /* `egetenv' may return a unibyte string, which will bite us since |
| 1039 | we expect the directory to be multibyte. */ | 1064 | we expect the directory to be multibyte. */ |
| 1040 | tem = build_string (newdir); | 1065 | tem = build_string (newdir); |
| 1041 | if (!STRING_MULTIBYTE (tem)) | 1066 | if (multibyte && !STRING_MULTIBYTE (tem)) |
| 1042 | { | 1067 | { |
| 1043 | hdir = DECODE_FILE (tem); | 1068 | hdir = DECODE_FILE (tem); |
| 1044 | newdir = SSDATA (hdir); | 1069 | newdir = SSDATA (hdir); |
| @@ -1060,7 +1085,18 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1060 | unblock_input (); | 1085 | unblock_input (); |
| 1061 | if (pw) | 1086 | if (pw) |
| 1062 | { | 1087 | { |
| 1088 | Lisp_Object tem; | ||
| 1089 | |||
| 1063 | newdir = pw->pw_dir; | 1090 | newdir = pw->pw_dir; |
| 1091 | /* `getpwnam' may return a unibyte string, which will | ||
| 1092 | bite us since we expect the directory to be | ||
| 1093 | multibyte. */ | ||
| 1094 | tem = build_string (newdir); | ||
| 1095 | if (multibyte && !STRING_MULTIBYTE (tem)) | ||
| 1096 | { | ||
| 1097 | hdir = DECODE_FILE (tem); | ||
| 1098 | newdir = SSDATA (hdir); | ||
| 1099 | } | ||
| 1064 | nm = p; | 1100 | nm = p; |
| 1065 | #ifdef DOS_NT | 1101 | #ifdef DOS_NT |
| 1066 | collapse_newdir = 0; | 1102 | collapse_newdir = 0; |
| @@ -1084,6 +1120,13 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1084 | adir = alloca (MAXPATHLEN + 1); | 1120 | adir = alloca (MAXPATHLEN + 1); |
| 1085 | if (!getdefdir (c_toupper (drive) - 'A' + 1, adir)) | 1121 | if (!getdefdir (c_toupper (drive) - 'A' + 1, adir)) |
| 1086 | adir = NULL; | 1122 | adir = NULL; |
| 1123 | else if (multibyte) | ||
| 1124 | { | ||
| 1125 | Lisp_Object tem = build_string (adir); | ||
| 1126 | |||
| 1127 | tem = DECODE_FILE (tem); | ||
| 1128 | memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); | ||
| 1129 | } | ||
| 1087 | } | 1130 | } |
| 1088 | if (!adir) | 1131 | if (!adir) |
| 1089 | { | 1132 | { |
| @@ -1142,6 +1185,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1142 | indirectly by prepending newdir to nm if necessary, and using | 1185 | indirectly by prepending newdir to nm if necessary, and using |
| 1143 | cwd (or the wd of newdir's drive) as the new newdir. */ | 1186 | cwd (or the wd of newdir's drive) as the new newdir. */ |
| 1144 | char *adir; | 1187 | char *adir; |
| 1188 | |||
| 1145 | if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1])) | 1189 | if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1])) |
| 1146 | { | 1190 | { |
| 1147 | drive = (unsigned char) newdir[0]; | 1191 | drive = (unsigned char) newdir[0]; |
| @@ -1151,7 +1195,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1151 | { | 1195 | { |
| 1152 | ptrdiff_t newlen = strlen (newdir); | 1196 | ptrdiff_t newlen = strlen (newdir); |
| 1153 | char *tmp = alloca (newlen + strlen (nm) + 2); | 1197 | char *tmp = alloca (newlen + strlen (nm) + 2); |
| 1154 | file_name_as_directory (tmp, newdir, newlen); | 1198 | file_name_as_directory (tmp, newdir, newlen, multibyte); |
| 1155 | strcat (tmp, nm); | 1199 | strcat (tmp, nm); |
| 1156 | nm = tmp; | 1200 | nm = tmp; |
| 1157 | } | 1201 | } |
| @@ -1159,10 +1203,17 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1159 | if (drive) | 1203 | if (drive) |
| 1160 | { | 1204 | { |
| 1161 | if (!getdefdir (c_toupper (drive) - 'A' + 1, adir)) | 1205 | if (!getdefdir (c_toupper (drive) - 'A' + 1, adir)) |
| 1162 | newdir = "/"; | 1206 | strcpy (adir, "/"); |
| 1163 | } | 1207 | } |
| 1164 | else | 1208 | else |
| 1165 | getwd (adir); | 1209 | getwd (adir); |
| 1210 | if (multibyte) | ||
| 1211 | { | ||
| 1212 | Lisp_Object tem = build_string (adir); | ||
| 1213 | |||
| 1214 | tem = DECODE_FILE (tem); | ||
| 1215 | memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); | ||
| 1216 | } | ||
| 1166 | newdir = adir; | 1217 | newdir = adir; |
| 1167 | } | 1218 | } |
| 1168 | 1219 | ||
| @@ -1249,7 +1300,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1249 | strcpy (target, newdir); | 1300 | strcpy (target, newdir); |
| 1250 | } | 1301 | } |
| 1251 | else | 1302 | else |
| 1252 | file_name_as_directory (target, newdir, length); | 1303 | file_name_as_directory (target, newdir, length, multibyte); |
| 1253 | } | 1304 | } |
| 1254 | 1305 | ||
| 1255 | strcat (target, nm); | 1306 | strcat (target, nm); |
| @@ -1335,9 +1386,14 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1335 | target[1] = ':'; | 1386 | target[1] = ':'; |
| 1336 | } | 1387 | } |
| 1337 | result = make_specified_string (target, -1, o - target, multibyte); | 1388 | result = make_specified_string (target, -1, o - target, multibyte); |
| 1338 | result = ENCODE_FILE (result); | 1389 | if (multibyte) |
| 1339 | dostounix_filename (SSDATA (result)); | 1390 | { |
| 1340 | result = DECODE_FILE (result); | 1391 | result = ENCODE_FILE (result); |
| 1392 | dostounix_filename (SSDATA (result)); | ||
| 1393 | result = DECODE_FILE (result); | ||
| 1394 | } | ||
| 1395 | else | ||
| 1396 | dostounix_filename (SSDATA (result)); | ||
| 1341 | #else /* !DOS_NT */ | 1397 | #else /* !DOS_NT */ |
| 1342 | result = make_specified_string (target, -1, o - target, multibyte); | 1398 | result = make_specified_string (target, -1, o - target, multibyte); |
| 1343 | #endif /* !DOS_NT */ | 1399 | #endif /* !DOS_NT */ |
| @@ -1619,18 +1675,24 @@ those `/' is discarded. */) | |||
| 1619 | memcpy (nm, SDATA (filename), SBYTES (filename) + 1); | 1675 | memcpy (nm, SDATA (filename), SBYTES (filename) + 1); |
| 1620 | 1676 | ||
| 1621 | #ifdef DOS_NT | 1677 | #ifdef DOS_NT |
| 1622 | { | 1678 | if (multibyte) |
| 1623 | Lisp_Object encoded_filename = ENCODE_FILE (filename); | 1679 | { |
| 1624 | Lisp_Object tem_fn; | 1680 | Lisp_Object encoded_filename = ENCODE_FILE (filename); |
| 1625 | 1681 | Lisp_Object tem_fn; | |
| 1626 | dostounix_filename (SDATA (encoded_filename)); | 1682 | |
| 1627 | tem_fn = DECODE_FILE (encoded_filename); | 1683 | dostounix_filename (SDATA (encoded_filename)); |
| 1628 | nm = alloca (SBYTES (tem_fn) + 1); | 1684 | tem_fn = DECODE_FILE (encoded_filename); |
| 1629 | memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1); | 1685 | nm = alloca (SBYTES (tem_fn) + 1); |
| 1630 | substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); | 1686 | memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1); |
| 1631 | if (substituted) | 1687 | substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); |
| 1632 | filename = tem_fn; | 1688 | if (substituted) |
| 1633 | } | 1689 | filename = tem_fn; |
| 1690 | } | ||
| 1691 | else | ||
| 1692 | { | ||
| 1693 | dostounix_filename (nm); | ||
| 1694 | substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); | ||
| 1695 | } | ||
| 1634 | #endif | 1696 | #endif |
| 1635 | endp = nm + SBYTES (filename); | 1697 | endp = nm + SBYTES (filename); |
| 1636 | 1698 | ||