comparison src/nt.c @ 2526:902d5bd9b75c

[xemacs-hg @ 2005-01-28 02:36:11 by ben] Support symlinks under Windows nt.c, fileio.c: Fix sync comments. config.h.in, dired-msw.c, emacs.c, event-msw.c, fileio.c, glyphs.c, lisp.h, nt.c, process-nt.c, realpath.c, sound.c, symsinit.h, sysdep.c, sysfile.h, syswindows.h, win32.c: Add support for treating shortcuts under Windows as symbolic links. Enabled with mswindows-shortcuts-are-links (t by default). Rewrite lots of places to use PATHNAME_CONVERT_OUT, which is moved to sysfile.h. Add PATHNAME_RESOLVE_LINKS, which only does things under Windows. Add profiling section for expand_file_name calls. nt.c, sysdep.c: Unicode-ize. realpath.c: Renamed from readlink_and_correct_case. Fix some problems with Windows implementation due to incorrect understanding of workings of the function. sound.c, ntplay.c, sound.h: Rename play_sound_file to nt_play_sound_file and pass internally-formatted data to it to avoid converting out and back again. text.h: is_c -> is_ascii.
author ben
date Fri, 28 Jan 2005 02:36:28 +0000
parents ab71ad6ff3dd
children 5eb04c84c7ae
comparison
equal deleted inserted replaced
2525:52f00344a629 2526:902d5bd9b75c
28 Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> 28 Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org>
29 (Note: Sync messages from Marc Paquette may indicate 29 (Note: Sync messages from Marc Paquette may indicate
30 incomplete synching, so beware.) 30 incomplete synching, so beware.)
31 Synched (completely!) with Emacs 20.6 by Ben Wing, 6-23-00. 31 Synched (completely!) with Emacs 20.6 by Ben Wing, 6-23-00.
32 Largely rewritten by Ben Wing for XEmacs Mule support. 32 Largely rewritten by Ben Wing for XEmacs Mule support.
33 Synched (completely!) with Emacs 21.1.103 by Ben Wing, 6-13-01. 33 Synched (completely!) with Emacs 21.0.103 by Ben Wing, 6-13-01.
34 */ 34 */
35 35
36 /* This file Mule-ized by Ben Wing, 6-23-00. */ 36 /* This file Mule-ized by Ben Wing, 6-23-00. */
37 37
38 #include <config.h> 38 #include <config.h>
293 293
294 /* must be valid filename, no wild cards or other invalid characters */ 294 /* must be valid filename, no wild cards or other invalid characters */
295 if (qxestrpbrk (name, "*?|<>\"")) 295 if (qxestrpbrk (name, "*?|<>\""))
296 return 0; 296 return 0;
297 297
298 C_STRING_TO_TSTR (name, nameext); 298 PATHNAME_CONVERT_OUT (name, nameext);
299 dir_handle = qxeFindFirstFile (nameext, &find_data); 299 dir_handle = qxeFindFirstFile (nameext, &find_data);
300 if (dir_handle != INVALID_HANDLE_VALUE) 300 if (dir_handle != INVALID_HANDLE_VALUE)
301 { 301 {
302 Ibyte *fileint; 302 Ibyte *fileint;
303 303
661 { 661 {
662 Extbyte remote_name[256 * XETCHAR_SIZE]; 662 Extbyte remote_name[256 * XETCHAR_SIZE];
663 Ibyte drive[3] = { root_dir[0], ':' }; 663 Ibyte drive[3] = { root_dir[0], ':' };
664 Extbyte *driveext; 664 Extbyte *driveext;
665 665
666 C_STRING_TO_TSTR (drive, driveext); 666 PATHNAME_CONVERT_OUT (drive, driveext);
667 if (qxeWNetGetConnection (driveext, remote_name, 667 if (qxeWNetGetConnection (driveext, remote_name,
668 sizeof (remote_name) / XETCHAR_SIZE) 668 sizeof (remote_name) / XETCHAR_SIZE)
669 == NO_ERROR) 669 == NO_ERROR)
670 /* do something */ ; 670 /* do something */ ;
671 } 671 }
680 DWORD maxcomp; 680 DWORD maxcomp;
681 DWORD flags; 681 DWORD flags;
682 Extbyte type[256 * MAX_XETCHAR_SIZE]; 682 Extbyte type[256 * MAX_XETCHAR_SIZE];
683 Extbyte *rootdirext; 683 Extbyte *rootdirext;
684 684
685 C_STRING_TO_TSTR (root_dir, rootdirext); 685 PATHNAME_CONVERT_OUT (root_dir, rootdirext);
686 686
687 /* Info is not cached, or is stale. */ 687 /* Info is not cached, or is stale. */
688 if (!qxeGetVolumeInformation (rootdirext, 688 if (!qxeGetVolumeInformation (rootdirext,
689 name, sizeof (name) / XETCHAR_SIZE, 689 name, sizeof (name) / XETCHAR_SIZE,
690 &serialnum, 690 &serialnum,
867 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ 867 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
868 else if (dir_find_handle == INVALID_HANDLE_VALUE) 868 else if (dir_find_handle == INVALID_HANDLE_VALUE)
869 { 869 {
870 DECLARE_EISTRING (filename); 870 DECLARE_EISTRING (filename);
871 Ichar lastch; 871 Ichar lastch;
872 Extbyte *fileext;
872 873
873 eicpy_rawz (filename, dir_pathname); 874 eicpy_rawz (filename, dir_pathname);
874 lastch = eigetch_char (filename, eicharlen (filename) - 1); 875 lastch = eigetch_char (filename, eicharlen (filename) - 1);
875 if (!IS_DIRECTORY_SEP (lastch)) 876 if (!IS_DIRECTORY_SEP (lastch))
876 eicat_ch (filename, '\\'); 877 eicat_ch (filename, '\\');
877 eicat_ch (filename, '*'); 878 eicat_ch (filename, '*');
878 eito_external (filename, Qmswindows_tstr); 879 PATHNAME_CONVERT_OUT (eidata (filename), fileext);
879 880
880 dir_find_handle = qxeFindFirstFile (eiextdata (filename), 881 dir_find_handle = qxeFindFirstFile (fileext, &dir_find_data);
881 &dir_find_data);
882 882
883 if (dir_find_handle == INVALID_HANDLE_VALUE) 883 if (dir_find_handle == INVALID_HANDLE_VALUE)
884 return NULL; 884 return NULL;
885 TSTR_TO_C_STRING (dir_find_data.cFileName, val); 885 TSTR_TO_C_STRING (dir_find_data.cFileName, val);
886 } 886 }
900 900
901 { 901 {
902 DECLARE_EISTRING (found); 902 DECLARE_EISTRING (found);
903 Bytecount namlen; 903 Bytecount namlen;
904 904
905 if (mswindows_shortcuts_are_symlinks)
906 {
907 int len = qxestrlen (val);
908 if (len > 4 && !qxestrcasecmp_ascii (val + len - 4, ".LNK"))
909 {
910 /* If we've found a valid link, then chop off the .LNK ending */
911 DECLARE_EISTRING (linkname);
912 Ichar lastch;
913 Ibyte *resolved;
914
915 /* First check if link is valid */
916 PATHNAME_RESOLVE_LINKS (dir_pathname, resolved);
917 eicpy_rawz (linkname, resolved);
918 lastch = eigetch_char (linkname, eicharlen (linkname) - 1);
919 if (!IS_DIRECTORY_SEP (lastch))
920 eicat_ch (linkname, '\\');
921 eicat_rawz (linkname, val);
922 resolved = mswindows_read_link (eidata (linkname));
923 if (resolved)
924 {
925 xfree (resolved, Ibyte *);
926 len -= 4;
927 val[len] = '\0';
928 }
929 }
930 }
931
905 eicpy_rawz (found, val); 932 eicpy_rawz (found, val);
906 if (need_to_free) 933 if (need_to_free)
907 xfree (val, Ibyte *); 934 xfree (val, Ibyte *);
908 935
909 if (!NILP (Vmswindows_downcase_file_names)) 936 if (!NILP (Vmswindows_downcase_file_names))
928 nr.dwScope = RESOURCE_GLOBALNET; 955 nr.dwScope = RESOURCE_GLOBALNET;
929 nr.dwType = RESOURCETYPE_DISK; 956 nr.dwType = RESOURCETYPE_DISK;
930 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; 957 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
931 nr.dwUsage = RESOURCEUSAGE_CONTAINER; 958 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
932 nr.lpLocalName = NULL; 959 nr.lpLocalName = NULL;
933 C_STRING_TO_TSTR (path, nr.lpRemoteName); 960 PATHNAME_CONVERT_OUT (path, nr.lpRemoteName);
934 nr.lpComment = NULL; 961 nr.lpComment = NULL;
935 nr.lpProvider = NULL; 962 nr.lpProvider = NULL;
936 963
937 result = qxeWNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 964 result = qxeWNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
938 RESOURCEUSAGE_CONNECTABLE, &nr, &henum); 965 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1021 } 1048 }
1022 else 1049 else
1023 { 1050 {
1024 Extbyte *pathext; 1051 Extbyte *pathext;
1025 1052
1026 C_STRING_TO_TSTR (path, pathext); 1053 PATHNAME_CONVERT_OUT (path, pathext);
1027 if ((attributes = qxeGetFileAttributes (pathext)) == -1) 1054 if ((attributes = qxeGetFileAttributes (pathext)) == -1)
1028 { 1055 {
1029 /* Should try mapping GetLastError to errno; for now just indicate 1056 /* Should try mapping GetLastError to errno; for now just indicate
1030 that path doesn't exist. */ 1057 that path doesn't exist. */
1031 errno = EACCES; 1058 errno = EACCES;
1064 { 1091 {
1065 errno = ENOENT; 1092 errno = ENOENT;
1066 return -1; 1093 return -1;
1067 } 1094 }
1068 1095
1069 C_STRING_TO_TSTR (old, oldext); 1096 PATHNAME_CONVERT_OUT (old, oldext);
1070 fileh = qxeCreateFile (oldext, 0, 0, NULL, OPEN_EXISTING, 1097 fileh = qxeCreateFile (oldext, 0, 0, NULL, OPEN_EXISTING,
1071 FILE_FLAG_BACKUP_SEMANTICS, NULL); 1098 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1072 if (fileh != INVALID_HANDLE_VALUE) 1099 if (fileh != INVALID_HANDLE_VALUE)
1073 { 1100 {
1074 int wlen; 1101 int wlen;
1173 Extbyte *oldext, *tempext; 1200 Extbyte *oldext, *tempext;
1174 /* Force temp name to require a manufactured 8.3 alias - this 1201 /* Force temp name to require a manufactured 8.3 alias - this
1175 seems to make the second rename work properly. */ 1202 seems to make the second rename work properly. */
1176 qxesprintf (p, "_.%s.%u", o, i); 1203 qxesprintf (p, "_.%s.%u", o, i);
1177 i++; 1204 i++;
1178 C_STRING_TO_EXTERNAL (oldname, oldext, Qfile_name); 1205 PATHNAME_CONVERT_OUT (oldname, oldext);
1179 C_STRING_TO_EXTERNAL (temp, tempext, Qfile_name); 1206 PATHNAME_CONVERT_OUT (temp, tempext);
1180 result = rename (oldext, tempext); 1207 result = rename (oldext, tempext);
1181 } 1208 }
1182 /* This loop must surely terminate! */ 1209 /* This loop must surely terminate! */
1183 while (result < 0 && errno == EEXIST); 1210 while (result < 0 && errno == EEXIST);
1184 if (result < 0) 1211 if (result < 0)
1196 file, which is not always possible in the general case. (Consider 1223 file, which is not always possible in the general case. (Consider
1197 all the permutations of shared or subst'd drives, etc.) */ 1224 all the permutations of shared or subst'd drives, etc.) */
1198 { 1225 {
1199 Extbyte *newext, *tempext; 1226 Extbyte *newext, *tempext;
1200 1227
1201 C_STRING_TO_EXTERNAL (newname, newext, Qfile_name); 1228 PATHNAME_CONVERT_OUT (newname, newext);
1202 C_STRING_TO_EXTERNAL (temp, tempext, Qfile_name); 1229 PATHNAME_CONVERT_OUT (temp, tempext);
1203 result = rename (tempext, newext); 1230 if (XEUNICODE_P)
1204 1231 {
1205 if (result < 0 1232 result = _wrename ((const wchar_t *) tempext,
1206 && (errno == EEXIST || errno == EACCES) 1233 (const wchar_t *) newext);
1207 && _chmod (newext, 0666) == 0 1234 if (result < 0
1208 && _unlink (newext) == 0) 1235 && (errno == EEXIST || errno == EACCES)
1209 result = rename (tempext, newext); 1236 && _wchmod ((const wchar_t *) newext, 0666) == 0
1237 && _wunlink ((const wchar_t *) newext) == 0)
1238 result = _wrename ((const wchar_t *) tempext,
1239 (const wchar_t *) newext);
1240 }
1241 else
1242 {
1243 result = rename (tempext, newext);
1244 if (result < 0
1245 && (errno == EEXIST || errno == EACCES)
1246 && _chmod (newext, 0666) == 0
1247 && _unlink (newext) == 0)
1248 result = rename (tempext, newext);
1249 }
1210 } 1250 }
1211 1251
1212 return result; 1252 return result;
1213 } 1253 }
1214 1254
1215 int 1255 int
1216 mswindows_unlink (const Ibyte *path) 1256 mswindows_unlink (const Ibyte *path)
1217 { 1257 {
1218 Extbyte *pathout; 1258 Extbyte *pathout;
1219 1259
1220 C_STRING_TO_EXTERNAL (path, pathout, Qfile_name); 1260 PATHNAME_CONVERT_OUT (path, pathout);
1221 /* On Unix, unlink works without write permission. */ 1261 /* On Unix, unlink works without write permission. */
1222 _chmod (pathout, 0666); 1262 if (XEUNICODE_P)
1223 return _unlink (pathout); 1263 {
1264 _wchmod ((const wchar_t *) pathout, 0666);
1265 return _wunlink ((const wchar_t *) pathout);
1266 }
1267 else
1268 {
1269 _chmod (pathout, 0666);
1270 return _unlink (pathout);
1271 }
1224 } 1272 }
1225 1273
1226 static FILETIME utc_base_ft; 1274 static FILETIME utc_base_ft;
1227 static long double utc_base; 1275 static long double utc_base;
1228 static int init = 0; 1276 static int init = 0;
1508 } 1556 }
1509 else if (rootdir) 1557 else if (rootdir)
1510 { 1558 {
1511 if (!IS_DIRECTORY_SEP (name[len-1])) 1559 if (!IS_DIRECTORY_SEP (name[len-1]))
1512 qxestrcat (name, (Ibyte *) "\\"); 1560 qxestrcat (name, (Ibyte *) "\\");
1561 /* File has already been resolved and we don't want to do it again
1562 in case of lstat() */
1513 C_STRING_TO_TSTR (name, nameext); 1563 C_STRING_TO_TSTR (name, nameext);
1514 if (qxeGetDriveType (nameext) < 2) 1564 if (qxeGetDriveType (nameext) < 2)
1515 { 1565 {
1516 SetErrorMode (errm); 1566 SetErrorMode (errm);
1517 errno = ENOENT; 1567 errno = ENOENT;
1572 fake_inode = 0; /* this doesn't either I think */ 1622 fake_inode = 0; /* this doesn't either I think */
1573 } 1623 }
1574 else 1624 else
1575 { 1625 {
1576 if (!NILP (Vmswindows_get_true_file_attributes)) 1626 if (!NILP (Vmswindows_get_true_file_attributes))
1627 /* File has already been resolved and we don't want to do it again
1628 in case of lstat() */
1577 C_STRING_TO_TSTR (name, nameext); 1629 C_STRING_TO_TSTR (name, nameext);
1578 if (!NILP (Vmswindows_get_true_file_attributes) 1630 if (!NILP (Vmswindows_get_true_file_attributes)
1579 /* No access rights required to get info. */ 1631 /* No access rights required to get info. */
1580 && (fh = qxeCreateFile (nameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) 1632 && (fh = qxeCreateFile (nameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
1581 != INVALID_HANDLE_VALUE) 1633 != INVALID_HANDLE_VALUE)
1582 { 1634 {
1583 /* This is more accurate in terms of gettting the correct number 1635 /* This is more accurate in terms of getting the correct number
1584 of links, but is quite slow (it is noticable when Emacs is 1636 of links, but is quite slow (it is noticable when Emacs is
1585 making a list of file name completions). */ 1637 making a list of file name completions). */
1586 BY_HANDLE_FILE_INFORMATION info; 1638 BY_HANDLE_FILE_INFORMATION info;
1587 1639
1588 if (GetFileInformationByHandle (fh, &info)) 1640 if (GetFileInformationByHandle (fh, &info))
1621 /* Don't bother to make this information more accurate. */ 1673 /* Don't bother to make this information more accurate. */
1622 buf->st_mode = _S_IFREG; 1674 buf->st_mode = _S_IFREG;
1623 buf->st_nlink = 1; 1675 buf->st_nlink = 1;
1624 fake_inode = 0; 1676 fake_inode = 0;
1625 } 1677 }
1678
1679 if (mswindows_shortcuts_are_symlinks &&
1680 buf->st_mode == _S_IFREG)
1681 {
1682 len = qxestrlen (name);
1683 if (len > 4 && !qxestrcasecmp_ascii (name + len - 4, ".LNK"))
1684 {
1685 /* check if link is valid */
1686 Ibyte *resolved = mswindows_read_link (name);
1687 if (resolved)
1688 {
1689 xfree (resolved, Ibyte *);
1690 buf->st_mode = S_IFLNK;
1691 }
1692 }
1693 }
1626 } 1694 }
1627 1695
1628 SetErrorMode (errm); 1696 SetErrorMode (errm);
1629 1697
1630 #if 0 1698 #if 0
1696 { 1764 {
1697 deftime.modtime = deftime.actime = time (NULL); 1765 deftime.modtime = deftime.actime = time (NULL);
1698 times = &deftime; 1766 times = &deftime;
1699 } 1767 }
1700 1768
1701 LISP_STRING_TO_TSTR (path, filename); 1769 LISP_PATHNAME_CONVERT_OUT (path, filename);
1702 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */ 1770 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */
1703 #if 0 1771 #if 0
1704 /* Need write access to set times. */ 1772 /* Need write access to set times. */
1705 fh = qxeCreateFile (filename, GENERIC_WRITE, 1773 fh = qxeCreateFile (filename, GENERIC_WRITE,
1706 FILE_SHARE_READ | FILE_SHARE_WRITE, 1774 FILE_SHARE_READ | FILE_SHARE_WRITE,
1766 HANDLE file_mapping; 1834 HANDLE file_mapping;
1767 void *file_base; 1835 void *file_base;
1768 DWORD size, upper_size; 1836 DWORD size, upper_size;
1769 Extbyte *fileext; 1837 Extbyte *fileext;
1770 1838
1771 C_STRING_TO_TSTR (filename, fileext); 1839 PATHNAME_CONVERT_OUT (filename, fileext);
1772 1840
1773 file = qxeCreateFile (fileext, GENERIC_READ, FILE_SHARE_READ, NULL, 1841 file = qxeCreateFile (fileext, GENERIC_READ, FILE_SHARE_READ, NULL,
1774 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 1842 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1775 if (file == INVALID_HANDLE_VALUE) 1843 if (file == INVALID_HANDLE_VALUE)
1776 return FALSE; 1844 return FALSE;
1802 HANDLE file; 1870 HANDLE file;
1803 HANDLE file_mapping; 1871 HANDLE file_mapping;
1804 void *file_base; 1872 void *file_base;
1805 Extbyte *fileext; 1873 Extbyte *fileext;
1806 1874
1807 C_STRING_TO_TSTR (filename, fileext); 1875 PATHNAME_CONVERT_OUT (filename, fileext);
1808 1876
1809 file = qxeCreateFile (fileext, GENERIC_READ | GENERIC_WRITE, 0, NULL, 1877 file = qxeCreateFile (fileext, GENERIC_READ | GENERIC_WRITE, 0, NULL,
1810 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 1878 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1811 if (file == INVALID_HANDLE_VALUE) 1879 if (file == INVALID_HANDLE_VALUE)
1812 return FALSE; 1880 return FALSE;
2005 CHECK_STRING (filename); 2073 CHECK_STRING (filename);
2006 2074
2007 /* first expand it. */ 2075 /* first expand it. */
2008 filename = Fexpand_file_name (filename, Qnil); 2076 filename = Fexpand_file_name (filename, Qnil);
2009 2077
2010 LISP_STRING_TO_TSTR (filename, fileext); 2078 LISP_PATHNAME_CONVERT_OUT (filename, fileext);
2011 /* luckily, this returns the short version of each element in the path. */ 2079 /* luckily, this returns the short version of each element in the path. */
2012 if (qxeGetShortPathName (fileext, shortname, 2080 if (qxeGetShortPathName (fileext, shortname,
2013 sizeof (shortname) / XETCHAR_SIZE) == 0) 2081 sizeof (shortname) / XETCHAR_SIZE) == 0)
2014 return Qnil; 2082 return Qnil;
2015 2083
2119 /* Loop over all possible drive letters */ 2187 /* Loop over all possible drive letters */
2120 while (*drive <= 'Z') 2188 while (*drive <= 'Z')
2121 { 2189 {
2122 Extbyte *driveext; 2190 Extbyte *driveext;
2123 2191
2124 C_STRING_TO_TSTR (drive, driveext); 2192 PATHNAME_CONVERT_OUT (drive, driveext);
2125 2193
2126 /* Record if this drive letter refers to a fixed drive. */ 2194 /* Record if this drive letter refers to a fixed drive. */
2127 fixed_drives[DRIVE_INDEX (*drive)] = 2195 fixed_drives[DRIVE_INDEX (*drive)] =
2128 (qxeGetDriveType (driveext) == DRIVE_FIXED); 2196 (qxeGetDriveType (driveext) == DRIVE_FIXED);
2129 2197