Mercurial > hg > xemacs-beta
diff src/win32.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 | 3d8143fc88e1 |
children | b3ea9c582280 |
line wrap: on
line diff
--- a/src/win32.c Fri Jan 28 02:05:05 2005 +0000 +++ b/src/win32.c Fri Jan 28 02:36:28 2005 +0000 @@ -23,6 +23,8 @@ #include "buffer.h" #include "console-msw.h" +#include "hash.h" +#include "profile.h" #include "sysfile.h" #include "sysproc.h" @@ -46,7 +48,10 @@ nil means no, t means yes. */ Lisp_Object Vmswindows_downcase_file_names; +struct hash_table *mswindows_read_link_hash; + int mswindows_windows9x_p; +Boolint mswindows_shortcuts_are_symlinks; pfSwitchToThread_t xSwitchToThread; @@ -341,6 +346,7 @@ if (STRINGP (operation)) LISP_STRING_TO_TSTR (operation, opext); + /* #### What about path names, which may be links? */ if (STRINGP (parameters)) LISP_STRING_TO_TSTR (parameters, parmext); if (STRINGP (current_dir)) @@ -403,6 +409,228 @@ } #endif +struct read_link_hash +{ + Ibyte *resolved; + DWORD ticks; +}; + +static Ibyte * +mswindows_read_link_1 (const Ibyte *fname) +{ +#ifdef NO_CYGWIN_COM_SUPPORT + return NULL; +#else + Ibyte *retval = NULL; + Extbyte *fnameext; + HANDLE fh; + struct read_link_hash *rlh; + DWORD ticks; + + /* The call below to resolve a link is rather time-consuming. + I tried implementing a simple cache based on creation and write time + of the file, but that didn't help enough -- maybe 30% faster but still + a lot of time spent here. So just do something cheesy and don't + check again if we've recently (< a second) done so. */ + + if (!mswindows_read_link_hash) + mswindows_read_link_hash = make_string_hash_table (1000); + C_STRING_TO_TSTR (fname, fnameext); + + /* See if we can find a cached value. */ + + /* The intermediate cast fools gcc into not outputting strict-aliasing + complaints */ + ticks = GetTickCount (); + if (!gethash (fname, mswindows_read_link_hash, + (const void **) (void *) &rlh)) + { + rlh = xnew_and_zero (struct read_link_hash); + puthash (qxestrdup (fname), rlh, mswindows_read_link_hash); + } + else if (ticks - rlh->ticks < 1000) + { + return rlh->resolved ? qxestrdup (rlh->resolved) : NULL; + } + + rlh->ticks = ticks; + + /* Retrieve creation/write time of link file. */ + + /* No access rights required to get info. */ + if ((fh = qxeCreateFile (fnameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) + == INVALID_HANDLE_VALUE) + { + CloseHandle (fh); + return NULL; + } + + CloseHandle (fh); + + /* #### + + Note the following in the docs: + + Note: The IShellLink interface has an ANSI version + (IShellLinkA) and a Unicode version (IShellLinkW). The + version that will be used depends on whether you compile + for ANSI or Unicode. However, Microsoft® Windows 95 and + Microsoft® Windows 98 only support IShellLinkA. + + We haven't yet implemented COM support in the + Unicode-splitting library. I don't quite understand how + COM works yet, but it looks like what's happening is + that the ShellLink class implements both the IShellLinkA + and IShellLinkW interfaces. To make this work at + run-time, we have to do something like this: + + -- define a new interface qxeIShellLink that uses + Extbyte * instead of LPSTR or LPWSTR. (not totally + necessary since Extbyte * == LPSTR). + + -- define a new class qxeShellLink that implements + qxeIShellLink. the methods on this class need to create + a shadow ShellLink object to do all the real work, and + call the corresponding function from either the + IShellLinkA or IShellLinkW interfaces on this object, + depending on whether XEUNICODE_P is defined. + + -- with appropriate preprocessor magic, of course, we + could make things appear transparent; but we've decided + not to do preprocessor magic for the moment. + */ + + /* #### Not Unicode-split for the moment; we have to do it + ourselves. */ + if (XEUNICODE_P) + { + IShellLinkW *psl; + + if (CoCreateInstance ( + XECOMID (CLSID_ShellLink), + NULL, + CLSCTX_INPROC_SERVER, + XECOMID (IID_IShellLinkW), + &VOIDP_CAST (psl)) == S_OK) + { + IPersistFile *ppf; + + if (XECOMCALL2 (psl, QueryInterface, + XECOMID (IID_IPersistFile), + &VOIDP_CAST (ppf)) == S_OK) + { + Extbyte *fname_unicode; + WIN32_FIND_DATAW wfd; + LPWSTR resolved = alloca_array (WCHAR, PATH_MAX_EXTERNAL + 1); + + /* Always Unicode. Not obvious from the + IPersistFile documentation, but look under + "Shell Link" for example code. */ + fname_unicode = fnameext; + + if (XECOMCALL2 (ppf, Load, + (LPWSTR) fname_unicode, + STGM_READ) == S_OK && + /* #### YUCK! Docs read + + cchMaxPath + + Maximum number of bytes to copy to the buffer pointed + to by the pszFile parameter. + + But "cch" means "count of characters", not bytes. + I'll assume the doc writers messed up and the + programmer was correct. Also, this approach is safe + even if it's actually the other way around. */ +#if defined (CYGWIN_HEADERS) && W32API_INSTALLED_VER < W32API_VER(2,2) + /* Another Cygwin prototype error, + fixed in v2.2 of w32api */ + XECOMCALL4 (psl, GetPath, (LPSTR) resolved, + PATH_MAX_EXTERNAL, &wfd, 0) +#else + XECOMCALL4 (psl, GetPath, resolved, + PATH_MAX_EXTERNAL, &wfd, 0) +#endif + == S_OK) + TSTR_TO_C_STRING_MALLOC (resolved, retval); + + XECOMCALL0 (ppf, Release); + } + + XECOMCALL0 (psl, Release); + } + } + else + { + IShellLinkA *psl; + + if (CoCreateInstance ( + XECOMID (CLSID_ShellLink), + NULL, + CLSCTX_INPROC_SERVER, + XECOMID (IID_IShellLinkA), + &VOIDP_CAST (psl)) == S_OK) + { + IPersistFile *ppf; + + if (XECOMCALL2 (psl, QueryInterface, + XECOMID (IID_IPersistFile), + &VOIDP_CAST (ppf)) == S_OK) + { + Extbyte *fname_unicode; + WIN32_FIND_DATAA wfd; + LPSTR resolved = alloca_array (CHAR, PATH_MAX_EXTERNAL + 1); + + /* Always Unicode. Not obvious from the + IPersistFile documentation, but look under + "Shell Link" for example code. */ + C_STRING_TO_EXTERNAL (fname, fname_unicode, + Qmswindows_unicode); + + if (XECOMCALL2 (ppf, Load, + (LPWSTR) fname_unicode, + STGM_READ) == S_OK + && XECOMCALL4 (psl, GetPath, resolved, + PATH_MAX_EXTERNAL, &wfd, 0) == S_OK) + TSTR_TO_C_STRING_MALLOC (resolved, retval); + + XECOMCALL0 (ppf, Release); + } + + XECOMCALL0 (psl, Release); + } + } + + /* Cache newly found value */ + if (rlh->resolved) + xfree (rlh->resolved, Ibyte *); + rlh->resolved = retval ? qxestrdup (retval) : NULL; + + return retval; +#endif /* NO_CYGWIN_COM_SUPPORT */ +} + +/* Resolve a file that may be a shortcut. Accepts either a file ending + with .LNK or without the ending. If a shortcut is found, returns + a value that you must xfree(); otherwise NULL. */ + +Ibyte * +mswindows_read_link (const Ibyte *fname) +{ + int len = qxestrlen (fname); + if (len > 4 && !qxestrcasecmp_ascii (fname + len - 4, ".LNK")) + return mswindows_read_link_1 (fname); + else + { + DECLARE_EISTRING (name2); + + eicpy_rawz (name2, fname); + eicat_ascii (name2, ".LNK"); + return mswindows_read_link_1 (eidata (name2)); + } +} + + #if defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) /* setitimer() does not exist on native MS Windows, and appears broken @@ -414,7 +642,6 @@ mechanism for SIGCHLD. Yuck.) */ - /*--------------------------------------------------------------------*/ /* Signal support */ /*--------------------------------------------------------------------*/ @@ -664,11 +891,20 @@ void vars_of_win32 (void) { - DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /* + DEFVAR_LISP ("mswindows-downcase-file-names", + &Vmswindows_downcase_file_names /* Non-nil means convert all-upper case file names to lower case. This applies when performing completions and file name expansion. */ ); Vmswindows_downcase_file_names = Qnil; + + DEFVAR_BOOL ("mswindows-shortcuts-are-symlinks", + &mswindows_shortcuts_are_symlinks /* +Non-nil means shortcuts (.LNK files) are treated as symbolic links. +This works also for symlinks created under Cygwin, because they use .LNK +files to implement symbolic links. +*/ ); + mswindows_shortcuts_are_symlinks = 1; } void