diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 5 | ||||
| -rw-r--r-- | src/fileio.c | 283 |
2 files changed, 151 insertions, 137 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 2081beb13ec..75be9df4b12 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2008-04-12 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * fileio.c (Fexpand_file_name): Tighten the scope of `p' and `o' vars. | ||
| 4 | Relocate `nm' after calling DECODE_FILE, in case the GC was run. | ||
| 5 | |||
| 1 | 2008-04-11 Stefan Monnier <monnier@iro.umontreal.ca> | 6 | 2008-04-11 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 7 | ||
| 3 | * keymap.h (map_keymap_canonical): Declare. | 8 | * keymap.h (map_keymap_canonical): Declare. |
diff --git a/src/fileio.c b/src/fileio.c index f9f37404b1a..26b2ebdeee5 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -1042,11 +1042,13 @@ See also the function `substitute-in-file-name'. */) | |||
| 1042 | (name, default_directory) | 1042 | (name, default_directory) |
| 1043 | Lisp_Object name, default_directory; | 1043 | Lisp_Object name, default_directory; |
| 1044 | { | 1044 | { |
| 1045 | unsigned char *nm; | 1045 | /* These point to SDATA and need to be careful with string-relocation |
| 1046 | during GC (via DECODE_FILE). */ | ||
| 1047 | unsigned char *nm, *newdir; | ||
| 1048 | /* This should only point to alloca'd data. */ | ||
| 1049 | unsigned char *target; | ||
| 1046 | 1050 | ||
| 1047 | register unsigned char *newdir, *p, *o; | ||
| 1048 | int tlen; | 1051 | int tlen; |
| 1049 | unsigned char *target; | ||
| 1050 | struct passwd *pw; | 1052 | struct passwd *pw; |
| 1051 | #ifdef VMS | 1053 | #ifdef VMS |
| 1052 | unsigned char * colon = 0; | 1054 | unsigned char * colon = 0; |
| @@ -1103,43 +1105,45 @@ See also the function `substitute-in-file-name'. */) | |||
| 1103 | return call3 (handler, Qexpand_file_name, name, default_directory); | 1105 | return call3 (handler, Qexpand_file_name, name, default_directory); |
| 1104 | } | 1106 | } |
| 1105 | 1107 | ||
| 1106 | o = SDATA (default_directory); | 1108 | { |
| 1107 | 1109 | unsigned char *o = SDATA (default_directory); | |
| 1108 | /* Make sure DEFAULT_DIRECTORY is properly expanded. | 1110 | |
| 1109 | It would be better to do this down below where we actually use | 1111 | /* Make sure DEFAULT_DIRECTORY is properly expanded. |
| 1110 | default_directory. Unfortunately, calling Fexpand_file_name recursively | 1112 | It would be better to do this down below where we actually use |
| 1111 | could invoke GC, and the strings might be relocated. This would | 1113 | default_directory. Unfortunately, calling Fexpand_file_name recursively |
| 1112 | be annoying because we have pointers into strings lying around | 1114 | could invoke GC, and the strings might be relocated. This would |
| 1113 | that would need adjusting, and people would add new pointers to | 1115 | be annoying because we have pointers into strings lying around |
| 1114 | the code and forget to adjust them, resulting in intermittent bugs. | 1116 | that would need adjusting, and people would add new pointers to |
| 1115 | Putting this call here avoids all that crud. | 1117 | the code and forget to adjust them, resulting in intermittent bugs. |
| 1116 | 1118 | Putting this call here avoids all that crud. | |
| 1117 | The EQ test avoids infinite recursion. */ | 1119 | |
| 1118 | if (! NILP (default_directory) && !EQ (default_directory, name) | 1120 | The EQ test avoids infinite recursion. */ |
| 1119 | /* Save time in some common cases - as long as default_directory | 1121 | if (! NILP (default_directory) && !EQ (default_directory, name) |
| 1120 | is not relative, it can be canonicalized with name below (if it | 1122 | /* Save time in some common cases - as long as default_directory |
| 1121 | is needed at all) without requiring it to be expanded now. */ | 1123 | is not relative, it can be canonicalized with name below (if it |
| 1124 | is needed at all) without requiring it to be expanded now. */ | ||
| 1122 | #ifdef DOS_NT | 1125 | #ifdef DOS_NT |
| 1123 | /* Detect MSDOS file names with drive specifiers. */ | 1126 | /* Detect MSDOS file names with drive specifiers. */ |
| 1124 | && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])) | 1127 | && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) |
| 1128 | && IS_DIRECTORY_SEP (o[2])) | ||
| 1125 | #ifdef WINDOWSNT | 1129 | #ifdef WINDOWSNT |
| 1126 | /* Detect Windows file names in UNC format. */ | 1130 | /* Detect Windows file names in UNC format. */ |
| 1127 | && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) | 1131 | && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1])) |
| 1128 | #endif | 1132 | #endif |
| 1129 | #else /* not DOS_NT */ | 1133 | #else /* not DOS_NT */ |
| 1130 | /* Detect Unix absolute file names (/... alone is not absolute on | 1134 | /* Detect Unix absolute file names (/... alone is not absolute on |
| 1131 | DOS or Windows). */ | 1135 | DOS or Windows). */ |
| 1132 | && ! (IS_DIRECTORY_SEP (o[0])) | 1136 | && ! (IS_DIRECTORY_SEP (o[0])) |
| 1133 | #endif /* not DOS_NT */ | 1137 | #endif /* not DOS_NT */ |
| 1134 | ) | 1138 | ) |
| 1135 | { | 1139 | { |
| 1136 | struct gcpro gcpro1; | 1140 | struct gcpro gcpro1; |
| 1137 | |||
| 1138 | GCPRO1 (name); | ||
| 1139 | default_directory = Fexpand_file_name (default_directory, Qnil); | ||
| 1140 | UNGCPRO; | ||
| 1141 | } | ||
| 1142 | 1141 | ||
| 1142 | GCPRO1 (name); | ||
| 1143 | default_directory = Fexpand_file_name (default_directory, Qnil); | ||
| 1144 | UNGCPRO; | ||
| 1145 | } | ||
| 1146 | } | ||
| 1143 | name = FILE_SYSTEM_CASE (name); | 1147 | name = FILE_SYSTEM_CASE (name); |
| 1144 | multibyte = STRING_MULTIBYTE (name); | 1148 | multibyte = STRING_MULTIBYTE (name); |
| 1145 | if (multibyte != STRING_MULTIBYTE (default_directory)) | 1149 | if (multibyte != STRING_MULTIBYTE (default_directory)) |
| @@ -1182,16 +1186,14 @@ See also the function `substitute-in-file-name'. */) | |||
| 1182 | "//somedir". */ | 1186 | "//somedir". */ |
| 1183 | if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | 1187 | if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) |
| 1184 | nm++; | 1188 | nm++; |
| 1185 | #endif /* WINDOWSNT */ | ||
| 1186 | #endif /* DOS_NT */ | ||
| 1187 | 1189 | ||
| 1188 | #ifdef WINDOWSNT | ||
| 1189 | /* Discard any previous drive specifier if nm is now in UNC format. */ | 1190 | /* Discard any previous drive specifier if nm is now in UNC format. */ |
| 1190 | if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) | 1191 | if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1])) |
| 1191 | { | 1192 | { |
| 1192 | drive = 0; | 1193 | drive = 0; |
| 1193 | } | 1194 | } |
| 1194 | #endif | 1195 | #endif /* WINDOWSNT */ |
| 1196 | #endif /* DOS_NT */ | ||
| 1195 | 1197 | ||
| 1196 | /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if | 1198 | /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if |
| 1197 | none are found, we can probably return right away. We will avoid | 1199 | none are found, we can probably return right away. We will avoid |
| @@ -1216,8 +1218,8 @@ See also the function `substitute-in-file-name'. */) | |||
| 1216 | non-zero value, that means we've discovered that we can't do | 1218 | non-zero value, that means we've discovered that we can't do |
| 1217 | that cool trick. */ | 1219 | that cool trick. */ |
| 1218 | int lose = 0; | 1220 | int lose = 0; |
| 1221 | unsigned char *p = nm; | ||
| 1219 | 1222 | ||
| 1220 | p = nm; | ||
| 1221 | while (*p) | 1223 | while (*p) |
| 1222 | { | 1224 | { |
| 1223 | /* Since we know the name is absolute, we can assume that each | 1225 | /* Since we know the name is absolute, we can assume that each |
| @@ -1389,8 +1391,12 @@ See also the function `substitute-in-file-name'. */) | |||
| 1389 | tem = build_string (newdir); | 1391 | tem = build_string (newdir); |
| 1390 | if (!STRING_MULTIBYTE (tem)) | 1392 | if (!STRING_MULTIBYTE (tem)) |
| 1391 | { | 1393 | { |
| 1394 | /* FIXME: DECODE_FILE may GC, which may move SDATA(name), | ||
| 1395 | after which `nm' won't point to the right place any more. */ | ||
| 1396 | int offset = nm - SDATA (name); | ||
| 1392 | hdir = DECODE_FILE (tem); | 1397 | hdir = DECODE_FILE (tem); |
| 1393 | newdir = SDATA (hdir); | 1398 | newdir = SDATA (hdir); |
| 1399 | nm = SDATA (name) + offset; | ||
| 1394 | } | 1400 | } |
| 1395 | #ifdef DOS_NT | 1401 | #ifdef DOS_NT |
| 1396 | collapse_newdir = 0; | 1402 | collapse_newdir = 0; |
| @@ -1401,12 +1407,13 @@ See also the function `substitute-in-file-name'. */) | |||
| 1401 | } | 1407 | } |
| 1402 | else /* ~user/filename */ | 1408 | else /* ~user/filename */ |
| 1403 | { | 1409 | { |
| 1410 | unsigned char *o, *p; | ||
| 1404 | for (p = nm; *p && (!IS_DIRECTORY_SEP (*p) | 1411 | for (p = nm; *p && (!IS_DIRECTORY_SEP (*p) |
| 1405 | #ifdef VMS | 1412 | #ifdef VMS |
| 1406 | && *p != ':' | 1413 | && *p != ':' |
| 1407 | #endif /* VMS */ | 1414 | #endif /* VMS */ |
| 1408 | ); p++); | 1415 | ); p++); |
| 1409 | o = (unsigned char *) alloca (p - nm + 1); | 1416 | o = alloca (p - nm + 1); |
| 1410 | bcopy ((char *) nm, o, p - nm); | 1417 | bcopy ((char *) nm, o, p - nm); |
| 1411 | o [p - nm] = 0; | 1418 | o [p - nm] = 0; |
| 1412 | 1419 | ||
| @@ -1618,120 +1625,122 @@ See also the function `substitute-in-file-name'. */) | |||
| 1618 | /* Now canonicalize by removing `//', `/.' and `/foo/..' if they | 1625 | /* Now canonicalize by removing `//', `/.' and `/foo/..' if they |
| 1619 | appear. */ | 1626 | appear. */ |
| 1620 | 1627 | ||
| 1621 | p = target; | 1628 | { |
| 1622 | o = target; | 1629 | unsigned char *p = target; |
| 1630 | unsigned char *o = target; | ||
| 1623 | 1631 | ||
| 1624 | while (*p) | 1632 | while (*p) |
| 1625 | { | 1633 | { |
| 1626 | #ifdef VMS | 1634 | #ifdef VMS |
| 1627 | if (*p != ']' && *p != '>' && *p != '-') | 1635 | if (*p != ']' && *p != '>' && *p != '-') |
| 1628 | { | 1636 | { |
| 1629 | if (*p == '\\') | 1637 | if (*p == '\\') |
| 1630 | p++; | 1638 | p++; |
| 1631 | *o++ = *p++; | 1639 | *o++ = *p++; |
| 1632 | } | 1640 | } |
| 1633 | else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) | 1641 | else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2) |
| 1634 | /* brackets are offset from each other by 2 */ | 1642 | /* brackets are offset from each other by 2 */ |
| 1635 | { | 1643 | { |
| 1636 | p += 2; | ||
| 1637 | if (*p != '.' && *p != '-' && o[-1] != '.') | ||
| 1638 | /* convert [foo][bar] to [bar] */ | ||
| 1639 | while (o[-1] != '[' && o[-1] != '<') | ||
| 1640 | o--; | ||
| 1641 | else if (*p == '-' && *o != '.') | ||
| 1642 | *--p = '.'; | ||
| 1643 | } | ||
| 1644 | else if (p[0] == '-' && o[-1] == '.' | ||
| 1645 | && (p[1] == '.' || p[1] == ']' || p[1] == '>')) | ||
| 1646 | /* flush .foo.- ; leave - if stopped by '[' or '<' */ | ||
| 1647 | { | ||
| 1648 | do | ||
| 1649 | o--; | ||
| 1650 | while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); | ||
| 1651 | if (p[1] == '.') /* foo.-.bar ==> bar. */ | ||
| 1652 | p += 2; | 1644 | p += 2; |
| 1653 | else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ | 1645 | if (*p != '.' && *p != '-' && o[-1] != '.') |
| 1654 | p++, o--; | 1646 | /* convert [foo][bar] to [bar] */ |
| 1655 | /* else [foo.-] ==> [-] */ | 1647 | while (o[-1] != '[' && o[-1] != '<') |
| 1656 | } | 1648 | o--; |
| 1657 | else | 1649 | else if (*p == '-' && *o != '.') |
| 1658 | { | 1650 | *--p = '.'; |
| 1651 | } | ||
| 1652 | else if (p[0] == '-' && o[-1] == '.' | ||
| 1653 | && (p[1] == '.' || p[1] == ']' || p[1] == '>')) | ||
| 1654 | /* flush .foo.- ; leave - if stopped by '[' or '<' */ | ||
| 1655 | { | ||
| 1656 | do | ||
| 1657 | o--; | ||
| 1658 | while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<'); | ||
| 1659 | if (p[1] == '.') /* foo.-.bar ==> bar. */ | ||
| 1660 | p += 2; | ||
| 1661 | else if (o[-1] == '.') /* '.foo.-]' ==> ']' */ | ||
| 1662 | p++, o--; | ||
| 1663 | /* else [foo.-] ==> [-] */ | ||
| 1664 | } | ||
| 1665 | else | ||
| 1666 | { | ||
| 1659 | #ifdef NO_HYPHENS_IN_FILENAMES | 1667 | #ifdef NO_HYPHENS_IN_FILENAMES |
| 1660 | if (*p == '-' | 1668 | if (*p == '-' |
| 1661 | && o[-1] != '[' && o[-1] != '<' && o[-1] != '.' | 1669 | && o[-1] != '[' && o[-1] != '<' && o[-1] != '.' |
| 1662 | && p[1] != ']' && p[1] != '>' && p[1] != '.') | 1670 | && p[1] != ']' && p[1] != '>' && p[1] != '.') |
| 1663 | *p = '_'; | 1671 | *p = '_'; |
| 1664 | #endif /* NO_HYPHENS_IN_FILENAMES */ | 1672 | #endif /* NO_HYPHENS_IN_FILENAMES */ |
| 1665 | *o++ = *p++; | 1673 | *o++ = *p++; |
| 1666 | } | 1674 | } |
| 1667 | #else /* not VMS */ | 1675 | #else /* not VMS */ |
| 1668 | if (!IS_DIRECTORY_SEP (*p)) | 1676 | if (!IS_DIRECTORY_SEP (*p)) |
| 1669 | { | 1677 | { |
| 1670 | *o++ = *p++; | 1678 | *o++ = *p++; |
| 1671 | } | 1679 | } |
| 1672 | else if (p[1] == '.' | 1680 | else if (p[1] == '.' |
| 1673 | && (IS_DIRECTORY_SEP (p[2]) | 1681 | && (IS_DIRECTORY_SEP (p[2]) |
| 1674 | || p[2] == 0)) | 1682 | || p[2] == 0)) |
| 1675 | { | 1683 | { |
| 1676 | /* If "/." is the entire filename, keep the "/". Otherwise, | 1684 | /* If "/." is the entire filename, keep the "/". Otherwise, |
| 1677 | just delete the whole "/.". */ | 1685 | just delete the whole "/.". */ |
| 1678 | if (o == target && p[2] == '\0') | 1686 | if (o == target && p[2] == '\0') |
| 1679 | *o++ = *p; | 1687 | *o++ = *p; |
| 1680 | p += 2; | 1688 | p += 2; |
| 1681 | } | 1689 | } |
| 1682 | else if (p[1] == '.' && p[2] == '.' | 1690 | else if (p[1] == '.' && p[2] == '.' |
| 1683 | /* `/../' is the "superroot" on certain file systems. | 1691 | /* `/../' is the "superroot" on certain file systems. |
| 1684 | Turned off on DOS_NT systems because they have no | 1692 | Turned off on DOS_NT systems because they have no |
| 1685 | "superroot" and because this causes us to produce | 1693 | "superroot" and because this causes us to produce |
| 1686 | file names like "d:/../foo" which fail file-related | 1694 | file names like "d:/../foo" which fail file-related |
| 1687 | functions of the underlying OS. (To reproduce, try a | 1695 | functions of the underlying OS. (To reproduce, try a |
| 1688 | long series of "../../" in default_directory, longer | 1696 | long series of "../../" in default_directory, longer |
| 1689 | than the number of levels from the root.) */ | 1697 | than the number of levels from the root.) */ |
| 1690 | #ifndef DOS_NT | 1698 | #ifndef DOS_NT |
| 1691 | && o != target | 1699 | && o != target |
| 1692 | #endif | 1700 | #endif |
| 1693 | && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) | 1701 | && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0)) |
| 1694 | { | 1702 | { |
| 1695 | while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) | 1703 | while (o != target && (--o) && !IS_DIRECTORY_SEP (*o)) |
| 1696 | ; | 1704 | ; |
| 1697 | /* Keep initial / only if this is the whole name. */ | 1705 | /* Keep initial / only if this is the whole name. */ |
| 1698 | if (o == target && IS_ANY_SEP (*o) && p[3] == 0) | 1706 | if (o == target && IS_ANY_SEP (*o) && p[3] == 0) |
| 1699 | ++o; | 1707 | ++o; |
| 1700 | p += 3; | 1708 | p += 3; |
| 1701 | } | 1709 | } |
| 1702 | else if (p > target && IS_DIRECTORY_SEP (p[1])) | 1710 | else if (p > target && IS_DIRECTORY_SEP (p[1])) |
| 1703 | /* Collapse multiple `/' in a row. */ | 1711 | /* Collapse multiple `/' in a row. */ |
| 1704 | p++; | 1712 | p++; |
| 1705 | else | 1713 | else |
| 1706 | { | 1714 | { |
| 1707 | *o++ = *p++; | 1715 | *o++ = *p++; |
| 1708 | } | 1716 | } |
| 1709 | #endif /* not VMS */ | 1717 | #endif /* not VMS */ |
| 1710 | } | 1718 | } |
| 1711 | 1719 | ||
| 1712 | #ifdef DOS_NT | 1720 | #ifdef DOS_NT |
| 1713 | /* At last, set drive name. */ | 1721 | /* At last, set drive name. */ |
| 1714 | #ifdef WINDOWSNT | 1722 | #ifdef WINDOWSNT |
| 1715 | /* Except for network file name. */ | 1723 | /* Except for network file name. */ |
| 1716 | if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))) | 1724 | if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))) |
| 1717 | #endif /* WINDOWSNT */ | 1725 | #endif /* WINDOWSNT */ |
| 1718 | { | 1726 | { |
| 1719 | if (!drive) abort (); | 1727 | if (!drive) abort (); |
| 1720 | target -= 2; | 1728 | target -= 2; |
| 1721 | target[0] = DRIVE_LETTER (drive); | 1729 | target[0] = DRIVE_LETTER (drive); |
| 1722 | target[1] = ':'; | 1730 | target[1] = ':'; |
| 1723 | } | 1731 | } |
| 1724 | /* Reinsert the escape prefix if required. */ | 1732 | /* Reinsert the escape prefix if required. */ |
| 1725 | if (is_escaped) | 1733 | if (is_escaped) |
| 1726 | { | 1734 | { |
| 1727 | target -= 2; | 1735 | target -= 2; |
| 1728 | target[0] = '/'; | 1736 | target[0] = '/'; |
| 1729 | target[1] = ':'; | 1737 | target[1] = ':'; |
| 1730 | } | 1738 | } |
| 1731 | CORRECT_DIR_SEPS (target); | 1739 | CORRECT_DIR_SEPS (target); |
| 1732 | #endif /* DOS_NT */ | 1740 | #endif /* DOS_NT */ |
| 1733 | 1741 | ||
| 1734 | result = make_specified_string (target, -1, o - target, multibyte); | 1742 | result = make_specified_string (target, -1, o - target, multibyte); |
| 1743 | } | ||
| 1735 | 1744 | ||
| 1736 | /* Again look to see if the file name has special constructs in it | 1745 | /* Again look to see if the file name has special constructs in it |
| 1737 | and perhaps call the corresponding file handler. This is needed | 1746 | and perhaps call the corresponding file handler. This is needed |