Mercurial > hg > xemacs-beta
comparison 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 |
comparison
equal
deleted
inserted
replaced
2525:52f00344a629 | 2526:902d5bd9b75c |
---|---|
21 #include <config.h> | 21 #include <config.h> |
22 #include "lisp.h" | 22 #include "lisp.h" |
23 | 23 |
24 #include "buffer.h" | 24 #include "buffer.h" |
25 #include "console-msw.h" | 25 #include "console-msw.h" |
26 #include "hash.h" | |
27 #include "profile.h" | |
26 | 28 |
27 #include "sysfile.h" | 29 #include "sysfile.h" |
28 #include "sysproc.h" | 30 #include "sysproc.h" |
29 #include "syssignal.h" | 31 #include "syssignal.h" |
30 #include "systime.h" | 32 #include "systime.h" |
44 | 46 |
45 /* Control conversion of upper case file names to lower case. | 47 /* Control conversion of upper case file names to lower case. |
46 nil means no, t means yes. */ | 48 nil means no, t means yes. */ |
47 Lisp_Object Vmswindows_downcase_file_names; | 49 Lisp_Object Vmswindows_downcase_file_names; |
48 | 50 |
51 struct hash_table *mswindows_read_link_hash; | |
52 | |
49 int mswindows_windows9x_p; | 53 int mswindows_windows9x_p; |
54 Boolint mswindows_shortcuts_are_symlinks; | |
50 | 55 |
51 pfSwitchToThread_t xSwitchToThread; | 56 pfSwitchToThread_t xSwitchToThread; |
52 | 57 |
53 pfNetUserEnum_t xNetUserEnum; | 58 pfNetUserEnum_t xNetUserEnum; |
54 pfNetApiBufferFree_t xNetApiBufferFree; | 59 pfNetApiBufferFree_t xNetApiBufferFree; |
339 Extbyte *path = NULL; | 344 Extbyte *path = NULL; |
340 Extbyte *doc = NULL; | 345 Extbyte *doc = NULL; |
341 | 346 |
342 if (STRINGP (operation)) | 347 if (STRINGP (operation)) |
343 LISP_STRING_TO_TSTR (operation, opext); | 348 LISP_STRING_TO_TSTR (operation, opext); |
349 /* #### What about path names, which may be links? */ | |
344 if (STRINGP (parameters)) | 350 if (STRINGP (parameters)) |
345 LISP_STRING_TO_TSTR (parameters, parmext); | 351 LISP_STRING_TO_TSTR (parameters, parmext); |
346 if (STRINGP (current_dir)) | 352 if (STRINGP (current_dir)) |
347 LOCAL_FILE_FORMAT_TO_TSTR (current_dir, path); | 353 LOCAL_FILE_FORMAT_TO_TSTR (current_dir, path); |
348 if (STRINGP (document)) | 354 if (STRINGP (document)) |
401 LOCAL_TO_WIN32_FILE_FORMAT (p, p); | 407 LOCAL_TO_WIN32_FILE_FORMAT (p, p); |
402 return build_intstring (p); | 408 return build_intstring (p); |
403 } | 409 } |
404 #endif | 410 #endif |
405 | 411 |
412 struct read_link_hash | |
413 { | |
414 Ibyte *resolved; | |
415 DWORD ticks; | |
416 }; | |
417 | |
418 static Ibyte * | |
419 mswindows_read_link_1 (const Ibyte *fname) | |
420 { | |
421 #ifdef NO_CYGWIN_COM_SUPPORT | |
422 return NULL; | |
423 #else | |
424 Ibyte *retval = NULL; | |
425 Extbyte *fnameext; | |
426 HANDLE fh; | |
427 struct read_link_hash *rlh; | |
428 DWORD ticks; | |
429 | |
430 /* The call below to resolve a link is rather time-consuming. | |
431 I tried implementing a simple cache based on creation and write time | |
432 of the file, but that didn't help enough -- maybe 30% faster but still | |
433 a lot of time spent here. So just do something cheesy and don't | |
434 check again if we've recently (< a second) done so. */ | |
435 | |
436 if (!mswindows_read_link_hash) | |
437 mswindows_read_link_hash = make_string_hash_table (1000); | |
438 C_STRING_TO_TSTR (fname, fnameext); | |
439 | |
440 /* See if we can find a cached value. */ | |
441 | |
442 /* The intermediate cast fools gcc into not outputting strict-aliasing | |
443 complaints */ | |
444 ticks = GetTickCount (); | |
445 if (!gethash (fname, mswindows_read_link_hash, | |
446 (const void **) (void *) &rlh)) | |
447 { | |
448 rlh = xnew_and_zero (struct read_link_hash); | |
449 puthash (qxestrdup (fname), rlh, mswindows_read_link_hash); | |
450 } | |
451 else if (ticks - rlh->ticks < 1000) | |
452 { | |
453 return rlh->resolved ? qxestrdup (rlh->resolved) : NULL; | |
454 } | |
455 | |
456 rlh->ticks = ticks; | |
457 | |
458 /* Retrieve creation/write time of link file. */ | |
459 | |
460 /* No access rights required to get info. */ | |
461 if ((fh = qxeCreateFile (fnameext, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) | |
462 == INVALID_HANDLE_VALUE) | |
463 { | |
464 CloseHandle (fh); | |
465 return NULL; | |
466 } | |
467 | |
468 CloseHandle (fh); | |
469 | |
470 /* #### | |
471 | |
472 Note the following in the docs: | |
473 | |
474 Note: The IShellLink interface has an ANSI version | |
475 (IShellLinkA) and a Unicode version (IShellLinkW). The | |
476 version that will be used depends on whether you compile | |
477 for ANSI or Unicode. However, Microsoft® Windows 95 and | |
478 Microsoft® Windows 98 only support IShellLinkA. | |
479 | |
480 We haven't yet implemented COM support in the | |
481 Unicode-splitting library. I don't quite understand how | |
482 COM works yet, but it looks like what's happening is | |
483 that the ShellLink class implements both the IShellLinkA | |
484 and IShellLinkW interfaces. To make this work at | |
485 run-time, we have to do something like this: | |
486 | |
487 -- define a new interface qxeIShellLink that uses | |
488 Extbyte * instead of LPSTR or LPWSTR. (not totally | |
489 necessary since Extbyte * == LPSTR). | |
490 | |
491 -- define a new class qxeShellLink that implements | |
492 qxeIShellLink. the methods on this class need to create | |
493 a shadow ShellLink object to do all the real work, and | |
494 call the corresponding function from either the | |
495 IShellLinkA or IShellLinkW interfaces on this object, | |
496 depending on whether XEUNICODE_P is defined. | |
497 | |
498 -- with appropriate preprocessor magic, of course, we | |
499 could make things appear transparent; but we've decided | |
500 not to do preprocessor magic for the moment. | |
501 */ | |
502 | |
503 /* #### Not Unicode-split for the moment; we have to do it | |
504 ourselves. */ | |
505 if (XEUNICODE_P) | |
506 { | |
507 IShellLinkW *psl; | |
508 | |
509 if (CoCreateInstance ( | |
510 XECOMID (CLSID_ShellLink), | |
511 NULL, | |
512 CLSCTX_INPROC_SERVER, | |
513 XECOMID (IID_IShellLinkW), | |
514 &VOIDP_CAST (psl)) == S_OK) | |
515 { | |
516 IPersistFile *ppf; | |
517 | |
518 if (XECOMCALL2 (psl, QueryInterface, | |
519 XECOMID (IID_IPersistFile), | |
520 &VOIDP_CAST (ppf)) == S_OK) | |
521 { | |
522 Extbyte *fname_unicode; | |
523 WIN32_FIND_DATAW wfd; | |
524 LPWSTR resolved = alloca_array (WCHAR, PATH_MAX_EXTERNAL + 1); | |
525 | |
526 /* Always Unicode. Not obvious from the | |
527 IPersistFile documentation, but look under | |
528 "Shell Link" for example code. */ | |
529 fname_unicode = fnameext; | |
530 | |
531 if (XECOMCALL2 (ppf, Load, | |
532 (LPWSTR) fname_unicode, | |
533 STGM_READ) == S_OK && | |
534 /* #### YUCK! Docs read | |
535 | |
536 cchMaxPath | |
537 | |
538 Maximum number of bytes to copy to the buffer pointed | |
539 to by the pszFile parameter. | |
540 | |
541 But "cch" means "count of characters", not bytes. | |
542 I'll assume the doc writers messed up and the | |
543 programmer was correct. Also, this approach is safe | |
544 even if it's actually the other way around. */ | |
545 #if defined (CYGWIN_HEADERS) && W32API_INSTALLED_VER < W32API_VER(2,2) | |
546 /* Another Cygwin prototype error, | |
547 fixed in v2.2 of w32api */ | |
548 XECOMCALL4 (psl, GetPath, (LPSTR) resolved, | |
549 PATH_MAX_EXTERNAL, &wfd, 0) | |
550 #else | |
551 XECOMCALL4 (psl, GetPath, resolved, | |
552 PATH_MAX_EXTERNAL, &wfd, 0) | |
553 #endif | |
554 == S_OK) | |
555 TSTR_TO_C_STRING_MALLOC (resolved, retval); | |
556 | |
557 XECOMCALL0 (ppf, Release); | |
558 } | |
559 | |
560 XECOMCALL0 (psl, Release); | |
561 } | |
562 } | |
563 else | |
564 { | |
565 IShellLinkA *psl; | |
566 | |
567 if (CoCreateInstance ( | |
568 XECOMID (CLSID_ShellLink), | |
569 NULL, | |
570 CLSCTX_INPROC_SERVER, | |
571 XECOMID (IID_IShellLinkA), | |
572 &VOIDP_CAST (psl)) == S_OK) | |
573 { | |
574 IPersistFile *ppf; | |
575 | |
576 if (XECOMCALL2 (psl, QueryInterface, | |
577 XECOMID (IID_IPersistFile), | |
578 &VOIDP_CAST (ppf)) == S_OK) | |
579 { | |
580 Extbyte *fname_unicode; | |
581 WIN32_FIND_DATAA wfd; | |
582 LPSTR resolved = alloca_array (CHAR, PATH_MAX_EXTERNAL + 1); | |
583 | |
584 /* Always Unicode. Not obvious from the | |
585 IPersistFile documentation, but look under | |
586 "Shell Link" for example code. */ | |
587 C_STRING_TO_EXTERNAL (fname, fname_unicode, | |
588 Qmswindows_unicode); | |
589 | |
590 if (XECOMCALL2 (ppf, Load, | |
591 (LPWSTR) fname_unicode, | |
592 STGM_READ) == S_OK | |
593 && XECOMCALL4 (psl, GetPath, resolved, | |
594 PATH_MAX_EXTERNAL, &wfd, 0) == S_OK) | |
595 TSTR_TO_C_STRING_MALLOC (resolved, retval); | |
596 | |
597 XECOMCALL0 (ppf, Release); | |
598 } | |
599 | |
600 XECOMCALL0 (psl, Release); | |
601 } | |
602 } | |
603 | |
604 /* Cache newly found value */ | |
605 if (rlh->resolved) | |
606 xfree (rlh->resolved, Ibyte *); | |
607 rlh->resolved = retval ? qxestrdup (retval) : NULL; | |
608 | |
609 return retval; | |
610 #endif /* NO_CYGWIN_COM_SUPPORT */ | |
611 } | |
612 | |
613 /* Resolve a file that may be a shortcut. Accepts either a file ending | |
614 with .LNK or without the ending. If a shortcut is found, returns | |
615 a value that you must xfree(); otherwise NULL. */ | |
616 | |
617 Ibyte * | |
618 mswindows_read_link (const Ibyte *fname) | |
619 { | |
620 int len = qxestrlen (fname); | |
621 if (len > 4 && !qxestrcasecmp_ascii (fname + len - 4, ".LNK")) | |
622 return mswindows_read_link_1 (fname); | |
623 else | |
624 { | |
625 DECLARE_EISTRING (name2); | |
626 | |
627 eicpy_rawz (name2, fname); | |
628 eicat_ascii (name2, ".LNK"); | |
629 return mswindows_read_link_1 (eidata (name2)); | |
630 } | |
631 } | |
632 | |
633 | |
406 #if defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) | 634 #if defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) |
407 | 635 |
408 /* setitimer() does not exist on native MS Windows, and appears broken | 636 /* setitimer() does not exist on native MS Windows, and appears broken |
409 on Cygwin (random lockups when BROKEN_SIGIO is defined), so we | 637 on Cygwin (random lockups when BROKEN_SIGIO is defined), so we |
410 emulate in both cases by using multimedia timers. Furthermore, | 638 emulate in both cases by using multimedia timers. Furthermore, |
412 use the standard signalling mechanism -- so we have to emulate | 640 use the standard signalling mechanism -- so we have to emulate |
413 that, too. (But only for timeouts -- we have to use the standard | 641 that, too. (But only for timeouts -- we have to use the standard |
414 mechanism for SIGCHLD. Yuck.) | 642 mechanism for SIGCHLD. Yuck.) |
415 */ | 643 */ |
416 | 644 |
417 | |
418 /*--------------------------------------------------------------------*/ | 645 /*--------------------------------------------------------------------*/ |
419 /* Signal support */ | 646 /* Signal support */ |
420 /*--------------------------------------------------------------------*/ | 647 /*--------------------------------------------------------------------*/ |
421 | 648 |
422 #define sigmask(nsig) (1U << nsig) | 649 #define sigmask(nsig) (1U << nsig) |
662 } | 889 } |
663 | 890 |
664 void | 891 void |
665 vars_of_win32 (void) | 892 vars_of_win32 (void) |
666 { | 893 { |
667 DEFVAR_LISP ("mswindows-downcase-file-names", &Vmswindows_downcase_file_names /* | 894 DEFVAR_LISP ("mswindows-downcase-file-names", |
895 &Vmswindows_downcase_file_names /* | |
668 Non-nil means convert all-upper case file names to lower case. | 896 Non-nil means convert all-upper case file names to lower case. |
669 This applies when performing completions and file name expansion. | 897 This applies when performing completions and file name expansion. |
670 */ ); | 898 */ ); |
671 Vmswindows_downcase_file_names = Qnil; | 899 Vmswindows_downcase_file_names = Qnil; |
900 | |
901 DEFVAR_BOOL ("mswindows-shortcuts-are-symlinks", | |
902 &mswindows_shortcuts_are_symlinks /* | |
903 Non-nil means shortcuts (.LNK files) are treated as symbolic links. | |
904 This works also for symlinks created under Cygwin, because they use .LNK | |
905 files to implement symbolic links. | |
906 */ ); | |
907 mswindows_shortcuts_are_symlinks = 1; | |
672 } | 908 } |
673 | 909 |
674 void | 910 void |
675 init_win32 (void) | 911 init_win32 (void) |
676 { | 912 { |