aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-12-12 20:19:10 +0200
committerEli Zaretskii2013-12-12 20:19:10 +0200
commit01633a17e74e638f31ec71c3587481f0084574f2 (patch)
treeb41eb1c64d2c01cbf94130bcbf772c32f653333d /src
parentcf86e18b159f754d6e5537b7b9cbefc32297f7d2 (diff)
parent893fcd38e9ef6bcb50dd9e9ed1de7caf194f8a83 (diff)
downloademacs-01633a17e74e638f31ec71c3587481f0084574f2.tar.gz
emacs-01633a17e74e638f31ec71c3587481f0084574f2.zip
Support MS-Windows file names that use characters outside of ANSI codepage.
src/w32.c (get_file_security, set_file_security) (create_symbolic_link): Separate pointers and boolean flags for ANSI and Unicode APIs. Use the latter if w32_unicode_filenames is non-zero, else the former. (codepage_for_filenames, filename_to_utf16, ) (filename_from_utf16, filename_to_ansi, filename_from_ansi): New functions. (init_user_info): Allow $HOME and $SHELL to include non-ANSI characters. (normalize_filename): Lose the DBCS code, now works on UTF-8. Accept only one argument; all callers changed. (dostounix_filename): Remove the second argument, now works in UTF-8. All callers changed. (parse_root): Lose DBCS code. (get_long_basename, w32_get_short_filename, init_environment) (GetCachedVolumeInformation, sys_readdir, open_unc_volume) (read_unc_volume, logon_network_drive, faccessat, sys_chdir) (sys_chmod, sys_creat, sys_fopen, sys_link, sys_mkdir, sys_open) (sys_rename_replace, sys_rmdir, sys_unlink, stat_worker, utime) (is_symlink, readlink, chase_symlinks, w32_delayed_load): Work in Unicode mode if w32_unicode_filenames is non-zero, in ANSI mode otherwise. (ansi_encode_filename): New function. (get_emacs_configuration, get_emacs_configuration_options): Functions deleted. (add_volume_info, GetCachedVolumeInformation): Run the input file name through unixtodos_filename, to ensure it is stored and referenced in canonical form. (get_volume_info): Lose the DBCS code, now works in UTF-8. (logon_network_drive, sys_link, utime): Improve error handling. (sys_access): New function. (hashval, generate_inode_val): Unused functions deleted. (symlink, readlink, readlinkat): Lose DBCS code, now works in UTF-8. (check_windows_init_file): Convert error message from UTF-8 to ANSI codepage, for display in the message box. (globals_of_w32): Set w32_unicode_filenames according to the OS version. src/w32term.c (construct_drag_n_drop): Work in Unicode mode when w32_unicode_filenames is non-zero, ANSI mode otherwise. (syms_of_w32term): Declare w32-unicode-filenames. src/w32proc.c (new_child, delete_child): Remove code that handled unused pending_deletion and input_file members of the child struct. (create_child, sys_spawnve): Convert all file names to ANSI codepage. Use ANSI APIs explicitly; forcibly fail if any file name cannot be encoded in ANSI codepage. Don't use unixtodos_filename, mirror slashes by hand. (record_infile, record_pending_deletion): Functions deleted. (Fw32_short_file_name): Call w32_get_short_filename instead of GetShortPathName. src/w32notify.c (add_watch): Work in Unicode mode when w32_unicode_filenames is non-zero, ANSI mode otherwise. (Fw32notify_add_watch): Rewrite to avoid using GetFullPathName; instead, do the same with Lisp primitives. src/w32fns.c (file_dialog_callback, Fx_file_dialog) (Fsystem_move_file_to_trash, Fw32_shell_execute) (Ffile_system_info, Fdefault_printer_name): Work in Unicode mode when w32_unicode_filenames is non-zero, ANSI mode otherwise. (Fw32_shell_execute): Improve error reporting. (Fdefault_printer_name): Ifdef away for Cygwin. src/w32.h (struct _child_process): Remove input_file and pending_deletion members that are no longer used. (dostounix_filename, w32_get_short_filename, filename_from_ansi) (filename_to_ansi, filename_from_utf16, filename_to_utf16) (ansi_encode_filename): New and updated prototypes. src/unexw32.c (open_input_file, open_output_file, unexec): Use ANSI APIs explicitly. (unexec): Don't use dostounix_filename, it expects a file name in UTF-8. Instead, mirror backslashes by hand. Convert NEW_NAME to ANSI encoding. src/fileio.c (Ffile_name_directory, file_name_as_directory) (directory_file_name, Fexpand_file_name) (Fsubstitute_in_file_name) [WINDOWSNT]: Adapt to the change in arguments of dostounix_filename. (Fexpand_file_name) [WINDOWSNT]: Convert value of $HOME to UTF-8. use MAX_UTF8_PATH for size of file-name strings. (emacs_readlinkat): Build an explicitly unibyte string for file names. (syms_of_fileio) <file-name-coding-system> default-file-name-coding-system>: Mention MS-Windows peculiarities. src/emacs.c (init_cmdargs) [WINDOWSNT]: Convert argv[0] to UTF-8. (main) [WINDOWSNT]: Convert the argv[] elements that are files or directories to UTF-8. (decode_env_path) [WINDOWSNT]: Convert file names taken from the environment, and each element of the input PATH, to UTF-8. src/dired.c (file_attributes): Use build_unibyte_string explicitly to make Lisp strings from user and group names. src/coding.h (ENCODE_FILE, DECODE_FILE): Just call encode_file and decode_file. src/coding.c (decode_file_name, encode_file_name): New functions. src/termcap.c (tgetent): Adapt to the change in arguments of dostounix_filename. src/sysdep.c (sys_subshell) [WINDOWSNT]: Use MAX_UTF8_PATH for file names. src/msdos.c (dostounix_filename, init_environment): Adapt to the change in arguments of dostounix_filename. src/image.c (xpm_load, tiff_load, gif_load, imagemagick_load) [WINDOWSNT]: Encode file names passed to the image libraries in ANSI codepage. src/gnutls.c (Fgnutls_boot): Encode all file names passed to GnuTLS. [WINDOWSNT]: Convert file names to the current ANSI codepage. src/filelock.c (lock_file) [WINDOWSNT]: Adapt to the change in arguments of dostounix_filename. nt/inc/ms-w32.h (MAX_UTF8_PATH): New macro. (opendir, closedir, readdir, seekdir): Redirect to replacement functions. nt/inc/dirent.h: Make d_name[] be MAXNAMELEN*4 characters long. lisp/term/w32-win.el (w32-handle-dropped-file): lisp/startup.el (normal-top-level): lisp/net/browse-url.el (browse-url-file-url): lisp/dnd.el (dnd-get-local-file-name): On MS-Windows, encode and decode file names using 'utf-8' rather than file-name-coding-system. doc/emacs/mule.texi (File Name Coding): Document file-name encoding peculiarities on MS-Windows. doc/lispref/nonascii.texi (Encoding and I/O): Document file-name encoding peculiarities on MS-Windows. etc/NEWS: Mention support on MS-Windows of file names outside of the current locale. Fixes: debbugs:7100
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog125
-rw-r--r--src/coding.c49
-rw-r--r--src/coding.h24
-rw-r--r--src/dired.c4
-rw-r--r--src/emacs.c80
-rw-r--r--src/fileio.c55
-rw-r--r--src/filelock.c2
-rw-r--r--src/gnutls.c18
-rw-r--r--src/image.c15
-rw-r--r--src/msdos.c6
-rw-r--r--src/msdos.h2
-rw-r--r--src/sysdep.c4
-rw-r--r--src/termcap.c2
-rw-r--r--src/unexw32.c27
-rw-r--r--src/w32.c2599
-rw-r--r--src/w32.h21
-rw-r--r--src/w32fns.c667
-rw-r--r--src/w32notify.c96
-rw-r--r--src/w32proc.c137
-rw-r--r--src/w32term.c51
20 files changed, 2690 insertions, 1294 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index e0f9b9e8689..839630e93ea 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,128 @@
12013-12-12 Eli Zaretskii <eliz@gnu.org>
2
3 Support file names on MS-Windows that use characters outside of
4 the current system codepage. (Bug#7100)
5
6 * w32.c (get_file_security, set_file_security)
7 (create_symbolic_link): Separate pointers and boolean flags for
8 ANSI and Unicode APIs. Use the latter if w32_unicode_filenames is
9 non-zero, else the former.
10 (codepage_for_filenames, filename_to_utf16, )
11 (filename_from_utf16, filename_to_ansi, filename_from_ansi): New
12 functions.
13 (init_user_info): Allow $HOME and $SHELL to include non-ANSI
14 characters.
15 (normalize_filename): Lose the DBCS code, now works on UTF-8.
16 Accept only one argument; all callers changed.
17 (dostounix_filename): Remove the second argument, now works in
18 UTF-8. All callers changed.
19 (parse_root): Lose DBCS code.
20 (get_long_basename, w32_get_short_filename, init_environment)
21 (GetCachedVolumeInformation, sys_readdir, open_unc_volume)
22 (read_unc_volume, logon_network_drive, faccessat, sys_chdir)
23 (sys_chmod, sys_creat, sys_fopen, sys_link, sys_mkdir, sys_open)
24 (sys_rename_replace, sys_rmdir, sys_unlink, stat_worker, utime)
25 (is_symlink, readlink, chase_symlinks, w32_delayed_load): Work in
26 Unicode mode if w32_unicode_filenames is non-zero, in ANSI mode
27 otherwise.
28 (ansi_encode_filename): New function.
29 (get_emacs_configuration, get_emacs_configuration_options):
30 Functions deleted.
31 (add_volume_info, GetCachedVolumeInformation): Run the input file
32 name through unixtodos_filename, to ensure it is stored and
33 referenced in canonical form.
34 (get_volume_info): Lose the DBCS code, now works in UTF-8.
35 (logon_network_drive, sys_link, utime): Improve error handling.
36 (sys_access): New function.
37 (hashval, generate_inode_val): Unused functions deleted.
38 (symlink, readlink, readlinkat): Lose DBCS code, now works in UTF-8.
39 (check_windows_init_file): Convert error message from UTF-8 to
40 ANSI codepage, for display in the message box.
41 (globals_of_w32): Set w32_unicode_filenames according to the OS
42 version.
43
44 * w32term.c (construct_drag_n_drop): Work in Unicode mode when
45 w32_unicode_filenames is non-zero, ANSI mode otherwise.
46 (syms_of_w32term): Declare w32-unicode-filenames.
47
48 * w32proc.c (new_child, delete_child): Remove code that handled
49 unused pending_deletion and input_file members of the child struct.
50 (create_child, sys_spawnve): Convert all file names to ANSI
51 codepage. Use ANSI APIs explicitly; forcibly fail if any file
52 name cannot be encoded in ANSI codepage. Don't use
53 unixtodos_filename, mirror slashes by hand.
54 (record_infile, record_pending_deletion): Functions deleted.
55 (Fw32_short_file_name): Call w32_get_short_filename instead of
56 GetShortPathName.
57
58 * w32notify.c (add_watch): Work in Unicode mode when
59 w32_unicode_filenames is non-zero, ANSI mode otherwise.
60 (Fw32notify_add_watch): Rewrite to avoid using GetFullPathName;
61 instead, do the same with Lisp primitives.
62
63 * w32fns.c (file_dialog_callback, Fx_file_dialog)
64 (Fsystem_move_file_to_trash, Fw32_shell_execute)
65 (Ffile_system_info, Fdefault_printer_name): Work in Unicode mode
66 when w32_unicode_filenames is non-zero, ANSI mode otherwise.
67 (Fw32_shell_execute): Improve error reporting.
68 (Fdefault_printer_name): Ifdef away for Cygwin.
69
70 * w32.h (struct _child_process): Remove input_file and
71 pending_deletion members that are no longer used.
72 (dostounix_filename, w32_get_short_filename, filename_from_ansi)
73 (filename_to_ansi, filename_from_utf16, filename_to_utf16)
74 (ansi_encode_filename): New and updated prototypes.
75
76 * unexw32.c (open_input_file, open_output_file, unexec): Use ANSI
77 APIs explicitly.
78 (unexec): Don't use dostounix_filename, it expects a file name in
79 UTF-8. Instead, mirror backslashes by hand. Convert NEW_NAME to
80 ANSI encoding.
81
82 * fileio.c (Ffile_name_directory, file_name_as_directory)
83 (directory_file_name, Fexpand_file_name)
84 (Fsubstitute_in_file_name) [WINDOWSNT]: Adapt to the change in
85 arguments of dostounix_filename.
86 (Fexpand_file_name) [WINDOWSNT]: Convert value of $HOME to UTF-8.
87 use MAX_UTF8_PATH for size of file-name strings.
88 (emacs_readlinkat): Build an explicitly unibyte string for file
89 names.
90 (syms_of_fileio) <file-name-coding-system>
91 default-file-name-coding-system>: Mention MS-Windows peculiarities.
92
93 * emacs.c (init_cmdargs) [WINDOWSNT]: Convert argv[0] to UTF-8.
94 (main) [WINDOWSNT]: Convert the argv[] elements that are files or
95 directories to UTF-8.
96 (decode_env_path) [WINDOWSNT]: Convert file names taken from the
97 environment, and each element of the input PATH, to UTF-8.
98
99 * dired.c (file_attributes): Use build_unibyte_string explicitly
100 to make Lisp strings from user and group names.
101
102 * coding.h (ENCODE_FILE, DECODE_FILE): Just call encode_file and
103 decode_file.
104
105 * coding.c (decode_file_name, encode_file_name): New functions.
106
107 * termcap.c (tgetent): Adapt to the change in arguments of
108 dostounix_filename.
109
110 * sysdep.c (sys_subshell) [WINDOWSNT]: Use MAX_UTF8_PATH for file
111 names.
112
113 * msdos.c (dostounix_filename, init_environment): Adapt to the
114 change in arguments of dostounix_filename.
115
116 * image.c (xpm_load, tiff_load, gif_load, imagemagick_load)
117 [WINDOWSNT]: Encode file names passed to the image libraries in
118 ANSI codepage.
119
120 * gnutls.c (Fgnutls_boot): Encode all file names passed to GnuTLS.
121 [WINDOWSNT]: Convert file names to the current ANSI codepage.
122
123 * filelock.c (lock_file) [WINDOWSNT]: Adapt to the change in
124 arguments of dostounix_filename.
125
12013-12-12 Dmitry Antipov <dmantipov@yandex.ru> 1262013-12-12 Dmitry Antipov <dmantipov@yandex.ru>
2 127
3 * font.h (struct font_entity) [HAVE_NS]: New field to record 128 * font.h (struct font_entity) [HAVE_NS]: New field to record
diff --git a/src/coding.c b/src/coding.c
index 6c0633f2d93..4ee55f7c8e6 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -9490,6 +9490,55 @@ code_convert_string_norecord (Lisp_Object string, Lisp_Object coding_system,
9490 return code_convert_string (string, coding_system, Qt, encodep, 0, 1); 9490 return code_convert_string (string, coding_system, Qt, encodep, 0, 1);
9491} 9491}
9492 9492
9493/* Encode or decode a file name, to or from a unibyte string suitable
9494 for passing to C library functions. */
9495Lisp_Object
9496decode_file_name (Lisp_Object fname)
9497{
9498#ifdef WINDOWSNT
9499 /* The w32 build pretends to use UTF-8 for file-name encoding, and
9500 converts the file names either to UTF-16LE or to the system ANSI
9501 codepage internally, depending on the underlying OS; see w32.c. */
9502 if (! NILP (Fcoding_system_p (Qutf_8)))
9503 return code_convert_string_norecord (fname, Qutf_8, 0);
9504 return fname;
9505#else /* !WINDOWSNT */
9506 if (! NILP (Vfile_name_coding_system))
9507 return code_convert_string_norecord (fname, Vfile_name_coding_system, 0);
9508 else if (! NILP (Vdefault_file_name_coding_system))
9509 return code_convert_string_norecord (fname,
9510 Vdefault_file_name_coding_system, 0);
9511 else
9512 return fname;
9513#endif
9514}
9515
9516Lisp_Object
9517encode_file_name (Lisp_Object fname)
9518{
9519 /* This is especially important during bootstrap and dumping, when
9520 file-name encoding is not yet known, and therefore any non-ASCII
9521 file names are unibyte strings, and could only be thrashed if we
9522 try to encode them. */
9523 if (!STRING_MULTIBYTE (fname))
9524 return fname;
9525#ifdef WINDOWSNT
9526 /* The w32 build pretends to use UTF-8 for file-name encoding, and
9527 converts the file names either to UTF-16LE or to the system ANSI
9528 codepage internally, depending on the underlying OS; see w32.c. */
9529 if (! NILP (Fcoding_system_p (Qutf_8)))
9530 return code_convert_string_norecord (fname, Qutf_8, 1);
9531 return fname;
9532#else /* !WINDOWSNT */
9533 if (! NILP (Vfile_name_coding_system))
9534 return code_convert_string_norecord (fname, Vfile_name_coding_system, 1);
9535 else if (! NILP (Vdefault_file_name_coding_system))
9536 return code_convert_string_norecord (fname,
9537 Vdefault_file_name_coding_system, 1);
9538 else
9539 return fname;
9540#endif
9541}
9493 9542
9494DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string, 9543DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string,
9495 2, 4, 0, 9544 2, 4, 0,
diff --git a/src/coding.h b/src/coding.h
index 5a921e44950..39f9d62462b 100644
--- a/src/coding.h
+++ b/src/coding.h
@@ -670,27 +670,13 @@ struct coding_system
670 (code) = (s1 << 8) | s2; \ 670 (code) = (s1 << 8) | s2; \
671 } while (0) 671 } while (0)
672 672
673/* Encode the file name NAME using the specified coding system for 673/* Encode the file name NAME using the specified coding system
674 file names, if any. If NAME is a unibyte string, return NAME. */ 674 for file names, if any. */
675#define ENCODE_FILE(name) \ 675#define ENCODE_FILE(NAME) encode_file_name (NAME)
676 (! STRING_MULTIBYTE (name) \
677 ? name \
678 : (! NILP (Vfile_name_coding_system) \
679 ? code_convert_string_norecord (name, Vfile_name_coding_system, 1) \
680 : (! NILP (Vdefault_file_name_coding_system) \
681 ? code_convert_string_norecord (name, Vdefault_file_name_coding_system, 1) \
682 : name)))
683
684 676
685/* Decode the file name NAME using the specified coding system 677/* Decode the file name NAME using the specified coding system
686 for file names, if any. */ 678 for file names, if any. */
687#define DECODE_FILE(name) \ 679#define DECODE_FILE(NAME) decode_file_name (NAME)
688 (! NILP (Vfile_name_coding_system) \
689 ? code_convert_string_norecord (name, Vfile_name_coding_system, 0) \
690 : (! NILP (Vdefault_file_name_coding_system) \
691 ? code_convert_string_norecord (name, Vdefault_file_name_coding_system, 0) \
692 : name))
693
694 680
695/* Encode the string STR using the specified coding system 681/* Encode the string STR using the specified coding system
696 for system functions, if any. */ 682 for system functions, if any. */
@@ -718,6 +704,8 @@ extern Lisp_Object code_convert_string (Lisp_Object, Lisp_Object,
718 Lisp_Object, bool, bool, bool); 704 Lisp_Object, bool, bool, bool);
719extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object, 705extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object,
720 bool); 706 bool);
707extern Lisp_Object encode_file_name (Lisp_Object);
708extern Lisp_Object decode_file_name (Lisp_Object);
721extern Lisp_Object raw_text_coding_system (Lisp_Object); 709extern Lisp_Object raw_text_coding_system (Lisp_Object);
722extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object); 710extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object);
723extern Lisp_Object complement_process_encoding_system (Lisp_Object); 711extern Lisp_Object complement_process_encoding_system (Lisp_Object);
diff --git a/src/dired.c b/src/dired.c
index 1bdb171c4d0..9520104dbc1 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -958,11 +958,11 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
958 unblock_input (); 958 unblock_input ();
959 } 959 }
960 if (uname) 960 if (uname)
961 values[2] = DECODE_SYSTEM (build_string (uname)); 961 values[2] = DECODE_SYSTEM (build_unibyte_string (uname));
962 else 962 else
963 values[2] = make_fixnum_or_float (s.st_uid); 963 values[2] = make_fixnum_or_float (s.st_uid);
964 if (gname) 964 if (gname)
965 values[3] = DECODE_SYSTEM (build_string (gname)); 965 values[3] = DECODE_SYSTEM (build_unibyte_string (gname));
966 else 966 else
967 values[3] = make_fixnum_or_float (s.st_gid); 967 values[3] = make_fixnum_or_float (s.st_gid);
968 968
diff --git a/src/emacs.c b/src/emacs.c
index 3243c38a87a..9c5a33d5a89 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -36,6 +36,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
36#ifdef WINDOWSNT 36#ifdef WINDOWSNT
37#include <fcntl.h> 37#include <fcntl.h>
38#include <sys/socket.h> 38#include <sys/socket.h>
39#include <mbstring.h>
39#include "w32.h" 40#include "w32.h"
40#include "w32heap.h" 41#include "w32heap.h"
41#endif 42#endif
@@ -393,7 +394,20 @@ init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
393 initial_argv = argv; 394 initial_argv = argv;
394 initial_argc = argc; 395 initial_argc = argc;
395 396
397#ifdef WINDOWSNT
398 /* Must use argv[0] converted to UTF-8, as it begets many standard
399 file and directory names. */
400 {
401 char argv0[MAX_UTF8_PATH];
402
403 if (filename_from_ansi (argv[0], argv0) == 0)
404 raw_name = build_unibyte_string (argv0);
405 else
406 raw_name = build_unibyte_string (argv[0]);
407 }
408#else
396 raw_name = build_unibyte_string (argv[0]); 409 raw_name = build_unibyte_string (argv[0]);
410#endif
397 411
398 /* Add /: to the front of the name 412 /* Add /: to the front of the name
399 if it would otherwise be treated as magic. */ 413 if it would otherwise be treated as magic. */
@@ -795,6 +809,14 @@ main (int argc, char **argv)
795 809
796 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args)) 810 if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
797 { 811 {
812#ifdef WINDOWSNT
813 /* argv[] array is kept in its original ANSI codepage encoding,
814 we need to convert to UTF-8, for chdir to work. */
815 char newdir[MAX_UTF8_PATH];
816
817 filename_from_ansi (ch_to_dir, newdir);
818 ch_to_dir = newdir;
819#endif
798 original_pwd = get_current_dir_name (); 820 original_pwd = get_current_dir_name ();
799 if (chdir (ch_to_dir) != 0) 821 if (chdir (ch_to_dir) != 0)
800 { 822 {
@@ -1539,7 +1561,16 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1539 char *file; 1561 char *file;
1540 /* Handle -l loadup, args passed by Makefile. */ 1562 /* Handle -l loadup, args passed by Makefile. */
1541 if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args)) 1563 if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args))
1542 Vtop_level = list2 (intern_c_string ("load"), build_string (file)); 1564 {
1565#ifdef WINDOWSNT
1566 char file_utf8[MAX_UTF8_PATH];
1567
1568 if (filename_from_ansi (file, file_utf8) == 0)
1569 file = file_utf8;
1570#endif
1571 Vtop_level = list2 (intern_c_string ("load"),
1572 build_unibyte_string (file));
1573 }
1543 /* Unless next switch is -nl, load "loadup.el" first thing. */ 1574 /* Unless next switch is -nl, load "loadup.el" first thing. */
1544 if (! no_loadup) 1575 if (! no_loadup)
1545 Vtop_level = list2 (intern_c_string ("load"), 1576 Vtop_level = list2 (intern_c_string ("load"),
@@ -2185,9 +2216,15 @@ decode_env_path (const char *evarname, const char *defalt, bool empty)
2185 Lisp_Object empty_element = empty ? Qnil : build_string ("."); 2216 Lisp_Object empty_element = empty ? Qnil : build_string (".");
2186#ifdef WINDOWSNT 2217#ifdef WINDOWSNT
2187 bool defaulted = 0; 2218 bool defaulted = 0;
2188 const char *emacs_dir = egetenv ("emacs_dir");
2189 static const char *emacs_dir_env = "%emacs_dir%/"; 2219 static const char *emacs_dir_env = "%emacs_dir%/";
2190 const size_t emacs_dir_len = strlen (emacs_dir_env); 2220 const size_t emacs_dir_len = strlen (emacs_dir_env);
2221 const char *edir = egetenv ("emacs_dir");
2222 char emacs_dir[MAX_UTF8_PATH];
2223
2224 /* egetenv looks in process-environment, which holds the variables
2225 in their original system-locale encoding. We need emacs_dir to
2226 be in UTF-8. */
2227 filename_from_ansi (edir, emacs_dir);
2191#endif 2228#endif
2192 2229
2193 /* It's okay to use getenv here, because this function is only used 2230 /* It's okay to use getenv here, because this function is only used
@@ -2208,9 +2245,44 @@ decode_env_path (const char *evarname, const char *defalt, bool empty)
2208 /* Ensure values from the environment use the proper directory separator. */ 2245 /* Ensure values from the environment use the proper directory separator. */
2209 if (path) 2246 if (path)
2210 { 2247 {
2211 char *path_copy = alloca (strlen (path) + 1); 2248 char *path_copy;
2249
2250#ifdef WINDOWSNT
2251 char *path_utf8, *q, *d;
2252 int cnv_result;
2253
2254 /* Convert each element of PATH to UTF-8. */
2255 p = path_copy = alloca (strlen (path) + 1);
2212 strcpy (path_copy, path); 2256 strcpy (path_copy, path);
2213 dostounix_filename (path_copy, 0); 2257 d = path_utf8 = alloca (4 * strlen (path) + 1);
2258 *d = '\0';
2259 do {
2260 q = _mbschr (p, SEPCHAR);
2261 if (q)
2262 *q = '\0';
2263 cnv_result = filename_from_ansi (p, d);
2264 if (q)
2265 {
2266 *q++ = SEPCHAR;
2267 p = q;
2268 /* If conversion of this PATH elements fails, make sure
2269 destination pointer will stay put, thus effectively
2270 ignoring the offending element. */
2271 if (cnv_result == 0)
2272 {
2273 d += strlen (d);
2274 *d++ = SEPCHAR;
2275 }
2276 }
2277 else if (cnv_result != 0 && d > path_utf8)
2278 d[-1] = '\0'; /* remove last semi-colon and null-terminate PATH */
2279 } while (q);
2280 path_copy = path_utf8;
2281#else /* MSDOS */
2282 path_copy = alloca (strlen (path) + 1);
2283 strcpy (path_copy, path);
2284#endif
2285 dostounix_filename (path_copy);
2214 path = path_copy; 2286 path = path_copy;
2215 } 2287 }
2216#endif 2288#endif
diff --git a/src/fileio.c b/src/fileio.c
index a0603b490d9..8fb6129885c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -460,7 +460,8 @@ Given a Unix syntax file name, returns a string ending in slash. */)
460 strcat (res, "/"); 460 strcat (res, "/");
461 beg = res; 461 beg = res;
462 p = beg + strlen (beg); 462 p = beg + strlen (beg);
463 dostounix_filename (beg, 0); 463 dostounix_filename (beg);
464 /* FIXME: Figure out the multibyte vs unibyte stuff here. */
464 tem_fn = make_specified_string (beg, -1, p - beg, 465 tem_fn = make_specified_string (beg, -1, p - beg,
465 STRING_MULTIBYTE (filename)); 466 STRING_MULTIBYTE (filename));
466 } 467 }
@@ -471,7 +472,7 @@ Given a Unix syntax file name, returns a string ending in slash. */)
471 else if (STRING_MULTIBYTE (filename)) 472 else if (STRING_MULTIBYTE (filename))
472 { 473 {
473 tem_fn = make_specified_string (beg, -1, p - beg, 1); 474 tem_fn = make_specified_string (beg, -1, p - beg, 1);
474 dostounix_filename (SSDATA (tem_fn), 1); 475 dostounix_filename (SSDATA (tem_fn));
475#ifdef WINDOWSNT 476#ifdef WINDOWSNT
476 if (!NILP (Vw32_downcase_file_names)) 477 if (!NILP (Vw32_downcase_file_names))
477 tem_fn = Fdowncase (tem_fn); 478 tem_fn = Fdowncase (tem_fn);
@@ -479,7 +480,7 @@ Given a Unix syntax file name, returns a string ending in slash. */)
479 } 480 }
480 else 481 else
481 { 482 {
482 dostounix_filename (beg, 0); 483 dostounix_filename (beg);
483 tem_fn = make_specified_string (beg, -1, p - beg, 0); 484 tem_fn = make_specified_string (beg, -1, p - beg, 0);
484 } 485 }
485 return tem_fn; 486 return tem_fn;
@@ -583,7 +584,7 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen,
583 dst[srclen++] = DIRECTORY_SEP; 584 dst[srclen++] = DIRECTORY_SEP;
584 dst[srclen] = 0; 585 dst[srclen] = 0;
585#ifdef DOS_NT 586#ifdef DOS_NT
586 dostounix_filename (dst, multibyte); 587 dostounix_filename (dst);
587#endif 588#endif
588 return srclen; 589 return srclen;
589} 590}
@@ -652,7 +653,7 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte)
652 memcpy (dst, src, srclen); 653 memcpy (dst, src, srclen);
653 dst[srclen] = 0; 654 dst[srclen] = 0;
654#ifdef DOS_NT 655#ifdef DOS_NT
655 dostounix_filename (dst, multibyte); 656 dostounix_filename (dst);
656#endif 657#endif
657 return srclen; 658 return srclen;
658} 659}
@@ -1101,7 +1102,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1101#ifdef DOS_NT 1102#ifdef DOS_NT
1102 /* Make sure directories are all separated with /, but 1103 /* Make sure directories are all separated with /, but
1103 avoid allocation of a new string when not required. */ 1104 avoid allocation of a new string when not required. */
1104 dostounix_filename (nm, multibyte); 1105 dostounix_filename (nm);
1105#ifdef WINDOWSNT 1106#ifdef WINDOWSNT
1106 if (IS_DIRECTORY_SEP (nm[1])) 1107 if (IS_DIRECTORY_SEP (nm[1]))
1107 { 1108 {
@@ -1162,7 +1163,18 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1162 nm++; 1163 nm++;
1163 /* `egetenv' may return a unibyte string, which will bite us since 1164 /* `egetenv' may return a unibyte string, which will bite us since
1164 we expect the directory to be multibyte. */ 1165 we expect the directory to be multibyte. */
1165 tem = build_string (newdir); 1166#ifdef WINDOWSNT
1167 if (newdir[0])
1168 {
1169 char newdir_utf8[MAX_UTF8_PATH];
1170
1171 filename_from_ansi (newdir, newdir_utf8);
1172 tem = build_string (newdir_utf8);
1173 }
1174 else
1175#else
1176 tem = build_string (newdir);
1177#endif
1166 if (multibyte && !STRING_MULTIBYTE (tem)) 1178 if (multibyte && !STRING_MULTIBYTE (tem))
1167 { 1179 {
1168 hdir = DECODE_FILE (tem); 1180 hdir = DECODE_FILE (tem);
@@ -1286,6 +1298,11 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1286 indirectly by prepending newdir to nm if necessary, and using 1298 indirectly by prepending newdir to nm if necessary, and using
1287 cwd (or the wd of newdir's drive) as the new newdir. */ 1299 cwd (or the wd of newdir's drive) as the new newdir. */
1288 char *adir; 1300 char *adir;
1301#ifdef WINDOWSNT
1302 const int adir_size = MAX_UTF8_PATH;
1303#else
1304 const int adir_size = MAXPATHLEN + 1;
1305#endif
1289 1306
1290 if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1])) 1307 if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
1291 { 1308 {
@@ -1301,14 +1318,14 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1301 strcat (tmp, nm); 1318 strcat (tmp, nm);
1302 nm = tmp; 1319 nm = tmp;
1303 } 1320 }
1304 adir = alloca (MAXPATHLEN + 1); 1321 adir = alloca (adir_size);
1305 if (drive) 1322 if (drive)
1306 { 1323 {
1307 if (!getdefdir (c_toupper (drive) - 'A' + 1, adir)) 1324 if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
1308 strcpy (adir, "/"); 1325 strcpy (adir, "/");
1309 } 1326 }
1310 else 1327 else
1311 getcwd (adir, MAXPATHLEN + 1); 1328 getcwd (adir, adir_size);
1312 if (multibyte) 1329 if (multibyte)
1313 { 1330 {
1314 Lisp_Object tem = build_string (adir); 1331 Lisp_Object tem = build_string (adir);
@@ -1479,7 +1496,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1479 target[1] = ':'; 1496 target[1] = ':';
1480 } 1497 }
1481 result = make_specified_string (target, -1, o - target, multibyte); 1498 result = make_specified_string (target, -1, o - target, multibyte);
1482 dostounix_filename (SSDATA (result), multibyte); 1499 dostounix_filename (SSDATA (result));
1483#ifdef WINDOWSNT 1500#ifdef WINDOWSNT
1484 if (!NILP (Vw32_downcase_file_names)) 1501 if (!NILP (Vw32_downcase_file_names))
1485 result = Fdowncase (result); 1502 result = Fdowncase (result);
@@ -1763,7 +1780,7 @@ those `/' is discarded. */)
1763 nm = xlispstrdupa (filename); 1780 nm = xlispstrdupa (filename);
1764 1781
1765#ifdef DOS_NT 1782#ifdef DOS_NT
1766 dostounix_filename (nm, multibyte); 1783 dostounix_filename (nm);
1767 substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0); 1784 substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
1768#endif 1785#endif
1769 endp = nm + SBYTES (filename); 1786 endp = nm + SBYTES (filename);
@@ -2661,9 +2678,9 @@ emacs_readlinkat (int fd, char const *filename)
2661 if (!buf) 2678 if (!buf)
2662 return Qnil; 2679 return Qnil;
2663 2680
2664 val = build_string (buf); 2681 val = build_unibyte_string (buf);
2665 if (buf[0] == '/' && strchr (buf, ':')) 2682 if (buf[0] == '/' && strchr (buf, ':'))
2666 val = concat2 (build_string ("/:"), val); 2683 val = concat2 (build_unibyte_string ("/:"), val);
2667 if (buf != readlink_buf) 2684 if (buf != readlink_buf)
2668 xfree (buf); 2685 xfree (buf);
2669 val = DECODE_FILE (val); 2686 val = DECODE_FILE (val);
@@ -5858,7 +5875,11 @@ syms_of_fileio (void)
5858 5875
5859 DEFVAR_LISP ("file-name-coding-system", Vfile_name_coding_system, 5876 DEFVAR_LISP ("file-name-coding-system", Vfile_name_coding_system,
5860 doc: /* Coding system for encoding file names. 5877 doc: /* Coding system for encoding file names.
5861If it is nil, `default-file-name-coding-system' (which see) is used. */); 5878If it is nil, `default-file-name-coding-system' (which see) is used.
5879
5880On MS-Windows, the value of this variable is largely ignored if
5881\`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows
5882behaves as if file names were encoded in `utf-8'. */);
5862 Vfile_name_coding_system = Qnil; 5883 Vfile_name_coding_system = Qnil;
5863 5884
5864 DEFVAR_LISP ("default-file-name-coding-system", 5885 DEFVAR_LISP ("default-file-name-coding-system",
@@ -5869,7 +5890,11 @@ This variable is used only when `file-name-coding-system' is nil.
5869This variable is set/changed by the command `set-language-environment'. 5890This variable is set/changed by the command `set-language-environment'.
5870User should not set this variable manually, 5891User should not set this variable manually,
5871instead use `file-name-coding-system' to get a constant encoding 5892instead use `file-name-coding-system' to get a constant encoding
5872of file names regardless of the current language environment. */); 5893of file names regardless of the current language environment.
5894
5895On MS-Windows, the value of this variable is largely ignored if
5896\`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows
5897behaves as if file names were encoded in `utf-8'. */);
5873 Vdefault_file_name_coding_system = Qnil; 5898 Vdefault_file_name_coding_system = Qnil;
5874 5899
5875 DEFSYM (Qformat_decode, "format-decode"); 5900 DEFSYM (Qformat_decode, "format-decode");
diff --git a/src/filelock.c b/src/filelock.c
index 2f53047f526..82ffd5d172b 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -689,7 +689,7 @@ lock_file (Lisp_Object fn)
689 /* Ensure we have only '/' separators, to avoid problems with 689 /* Ensure we have only '/' separators, to avoid problems with
690 looking (inside fill_in_lock_file_name) for backslashes in file 690 looking (inside fill_in_lock_file_name) for backslashes in file
691 names encoded by some DBCS codepage. */ 691 names encoded by some DBCS codepage. */
692 dostounix_filename (SSDATA (fn), 1); 692 dostounix_filename (SSDATA (fn));
693#endif 693#endif
694 encoded_fn = ENCODE_FILE (fn); 694 encoded_fn = ENCODE_FILE (fn);
695 695
diff --git a/src/gnutls.c b/src/gnutls.c
index 5a296166cdd..9ea3f59100d 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 21
22#include "lisp.h" 22#include "lisp.h"
23#include "process.h" 23#include "process.h"
24#include "coding.h"
24 25
25#ifdef HAVE_GNUTLS 26#ifdef HAVE_GNUTLS
26#include <gnutls/gnutls.h> 27#include <gnutls/gnutls.h>
@@ -899,6 +900,13 @@ one trustfile (usually a CA bundle). */)
899 { 900 {
900 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ", 901 GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
901 SSDATA (trustfile)); 902 SSDATA (trustfile));
903 trustfile = ENCODE_FILE (trustfile);
904#ifdef WINDOWSNT
905 /* Since GnuTLS doesn't support UTF-8 or UTF-16 encoded
906 file names on Windows, we need to re-encode the file
907 name using the current ANSI codepage. */
908 trustfile = ansi_encode_filename (trustfile);
909#endif
902 ret = fn_gnutls_certificate_set_x509_trust_file 910 ret = fn_gnutls_certificate_set_x509_trust_file
903 (x509_cred, 911 (x509_cred,
904 SSDATA (trustfile), 912 SSDATA (trustfile),
@@ -921,6 +929,10 @@ one trustfile (usually a CA bundle). */)
921 { 929 {
922 GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ", 930 GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
923 SSDATA (crlfile)); 931 SSDATA (crlfile));
932 crlfile = ENCODE_FILE (crlfile);
933#ifdef WINDOWSNT
934 crlfile = ansi_encode_filename (crlfile);
935#endif
924 ret = fn_gnutls_certificate_set_x509_crl_file 936 ret = fn_gnutls_certificate_set_x509_crl_file
925 (x509_cred, SSDATA (crlfile), file_format); 937 (x509_cred, SSDATA (crlfile), file_format);
926 938
@@ -944,6 +956,12 @@ one trustfile (usually a CA bundle). */)
944 SSDATA (keyfile)); 956 SSDATA (keyfile));
945 GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ", 957 GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
946 SSDATA (certfile)); 958 SSDATA (certfile));
959 keyfile = ENCODE_FILE (keyfile);
960 certfile = ENCODE_FILE (certfile);
961#ifdef WINDOWSNT
962 keyfile = ansi_encode_filename (keyfile);
963 certfile = ansi_encode_filename (certfile);
964#endif
947 ret = fn_gnutls_certificate_set_x509_key_file 965 ret = fn_gnutls_certificate_set_x509_key_file
948 (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format); 966 (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format);
949 967
diff --git a/src/image.c b/src/image.c
index 91038dd480a..38a92277299 100644
--- a/src/image.c
+++ b/src/image.c
@@ -3590,6 +3590,12 @@ xpm_load (struct frame *f, struct image *img)
3590 } 3590 }
3591 3591
3592#ifdef HAVE_NTGUI 3592#ifdef HAVE_NTGUI
3593#ifdef WINDOWSNT
3594 /* FILE is encoded in UTF-8, but image libraries on Windows
3595 support neither UTF-8 nor UTF-16 encoded file names. So we
3596 need to re-encode it in ANSI. */
3597 file = ansi_encode_filename (file);
3598#endif
3593 /* XpmReadFileToPixmap is not available in the Windows port of 3599 /* XpmReadFileToPixmap is not available in the Windows port of
3594 libxpm. But XpmReadFileToImage almost does what we want. */ 3600 libxpm. But XpmReadFileToImage almost does what we want. */
3595 rc = fn_XpmReadFileToImage (&hdc, SDATA (file), 3601 rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
@@ -6968,6 +6974,9 @@ tiff_load (struct frame *f, struct image *img)
6968 image_error ("Cannot find image file `%s'", specified_file, Qnil); 6974 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6969 return 0; 6975 return 0;
6970 } 6976 }
6977#ifdef WINDOWSNT
6978 file = ansi_encode_filename (file);
6979#endif
6971 6980
6972 /* Try to open the image file. */ 6981 /* Try to open the image file. */
6973 tiff = fn_TIFFOpen (SSDATA (file), "r"); 6982 tiff = fn_TIFFOpen (SSDATA (file), "r");
@@ -7353,6 +7362,9 @@ gif_load (struct frame *f, struct image *img)
7353 image_error ("Cannot find image file `%s'", specified_file, Qnil); 7362 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7354 return 0; 7363 return 0;
7355 } 7364 }
7365#ifdef WINDOWSNT
7366 file = ansi_encode_filename (file);
7367#endif
7356 7368
7357 /* Open the GIF file. */ 7369 /* Open the GIF file. */
7358#if GIFLIB_MAJOR < 5 7370#if GIFLIB_MAJOR < 5
@@ -8479,6 +8491,9 @@ imagemagick_load (struct frame *f, struct image *img)
8479 image_error ("Cannot find image file `%s'", file_name, Qnil); 8491 image_error ("Cannot find image file `%s'", file_name, Qnil);
8480 return 0; 8492 return 0;
8481 } 8493 }
8494#ifdef WINDOWSNT
8495 file = ansi_encode_filename (file);
8496#endif
8482 success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file)); 8497 success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
8483 } 8498 }
8484 /* Else its not a file, its a lisp object. Load the image from a 8499 /* Else its not a file, its a lisp object. Load the image from a
diff --git a/src/msdos.c b/src/msdos.c
index 7a029f8c380..b778245a7be 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -3295,7 +3295,7 @@ void msdos_downcase_filename (unsigned char *);
3295/* Destructively turn backslashes into slashes. */ 3295/* Destructively turn backslashes into slashes. */
3296 3296
3297void 3297void
3298dostounix_filename (char *p, int ignore) 3298dostounix_filename (char *p)
3299{ 3299{
3300 msdos_downcase_filename (p); 3300 msdos_downcase_filename (p);
3301 3301
@@ -3559,7 +3559,7 @@ init_environment (int argc, char **argv, int skip_args)
3559 if (!s) s = "c:/command.com"; 3559 if (!s) s = "c:/command.com";
3560 t = alloca (strlen (s) + 1); 3560 t = alloca (strlen (s) + 1);
3561 strcpy (t, s); 3561 strcpy (t, s);
3562 dostounix_filename (t, 0); 3562 dostounix_filename (t);
3563 setenv ("SHELL", t, 0); 3563 setenv ("SHELL", t, 0);
3564 3564
3565 /* PATH is also downcased and backslashes mirrored. */ 3565 /* PATH is also downcased and backslashes mirrored. */
@@ -3569,7 +3569,7 @@ init_environment (int argc, char **argv, int skip_args)
3569 /* Current directory is always considered part of MsDos's path but it is 3569 /* Current directory is always considered part of MsDos's path but it is
3570 not normally mentioned. Now it is. */ 3570 not normally mentioned. Now it is. */
3571 strcat (strcpy (t, ".;"), s); 3571 strcat (strcpy (t, ".;"), s);
3572 dostounix_filename (t, 0); /* Not a single file name, but this should work. */ 3572 dostounix_filename (t); /* Not a single file name, but this should work. */
3573 setenv ("PATH", t, 1); 3573 setenv ("PATH", t, 1);
3574 3574
3575 /* In some sense all dos users have root privileges, so... */ 3575 /* In some sense all dos users have root privileges, so... */
diff --git a/src/msdos.h b/src/msdos.h
index 27090324b44..11d7eb5c3e1 100644
--- a/src/msdos.h
+++ b/src/msdos.h
@@ -29,7 +29,7 @@ void dos_set_window_size (int *, int *);
29 29
30int getdefdir (int, char*); 30int getdefdir (int, char*);
31void unixtodos_filename (char *); 31void unixtodos_filename (char *);
32void dostounix_filename (char *, int); 32void dostounix_filename (char *);
33char *rootrelativepath (char *); 33char *rootrelativepath (char *);
34void init_environment (int, char **, int); 34void init_environment (int, char **, int);
35void internal_terminal_init (void); 35void internal_terminal_init (void);
diff --git a/src/sysdep.c b/src/sysdep.c
index f78a8fbb2ef..7af4254fcc7 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -464,7 +464,11 @@ sys_subshell (void)
464{ 464{
465#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */ 465#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
466 int st; 466 int st;
467#ifdef MSDOS
467 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ 468 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
469#else
470 char oldwd[MAX_UTF8_PATH];
471#endif
468#endif 472#endif
469 pid_t pid; 473 pid_t pid;
470 int status; 474 int status;
diff --git a/src/termcap.c b/src/termcap.c
index aa225d9b3b1..f0819266318 100644
--- a/src/termcap.c
+++ b/src/termcap.c
@@ -393,7 +393,7 @@ tgetent (char *bp, const char *name)
393 if (termcap_name && (*termcap_name == '\\' 393 if (termcap_name && (*termcap_name == '\\'
394 || *termcap_name == '/' 394 || *termcap_name == '/'
395 || termcap_name[1] == ':')) 395 || termcap_name[1] == ':'))
396 dostounix_filename (termcap_name, 0); 396 dostounix_filename (termcap_name);
397#endif 397#endif
398 398
399 filep = termcap_name && valid_filename_p (termcap_name); 399 filep = termcap_name && valid_filename_p (termcap_name);
diff --git a/src/unexw32.c b/src/unexw32.c
index a01ac799592..3dfce22d757 100644
--- a/src/unexw32.c
+++ b/src/unexw32.c
@@ -120,6 +120,8 @@ _start (void)
120 120
121/* File handling. */ 121/* File handling. */
122 122
123/* Implementation note: this and the next functions work with ANSI
124 codepage encoded file names! */
123int 125int
124open_input_file (file_data *p_file, char *filename) 126open_input_file (file_data *p_file, char *filename)
125{ 127{
@@ -128,8 +130,8 @@ open_input_file (file_data *p_file, char *filename)
128 void *file_base; 130 void *file_base;
129 unsigned long size, upper_size; 131 unsigned long size, upper_size;
130 132
131 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, 133 file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
132 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 134 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
133 if (file == INVALID_HANDLE_VALUE) 135 if (file == INVALID_HANDLE_VALUE)
134 return FALSE; 136 return FALSE;
135 137
@@ -166,9 +168,9 @@ open_output_file (file_data *p_file, char *filename, unsigned long size)
166 creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard 168 creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
167 links to the same file, which defeats the purpose of these hard 169 links to the same file, which defeats the purpose of these hard
168 links: being able to run previous builds. */ 170 links: being able to run previous builds. */
169 DeleteFile (filename); 171 DeleteFileA (filename);
170 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 172 file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
171 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 173 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
172 if (file == INVALID_HANDLE_VALUE) 174 if (file == INVALID_HANDLE_VALUE)
173 return FALSE; 175 return FALSE;
174 176
@@ -722,23 +724,30 @@ void
722unexec (const char *new_name, const char *old_name) 724unexec (const char *new_name, const char *old_name)
723{ 725{
724 file_data in_file, out_file; 726 file_data in_file, out_file;
725 char out_filename[MAX_PATH], in_filename[MAX_PATH]; 727 char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
726 unsigned long size; 728 unsigned long size;
727 char *p; 729 char *p;
728 char *q; 730 char *q;
729 731
730 /* Ignore old_name, and get our actual location from the OS. */ 732 /* Ignore old_name, and get our actual location from the OS. */
731 if (!GetModuleFileName (NULL, in_filename, MAX_PATH)) 733 if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
732 abort (); 734 abort ();
733 dostounix_filename (in_filename, 0); 735
736 /* Can't use dostounix_filename here, since that needs its file name
737 argument encoded in UTF-8. */
738 for (p = in_filename; *p; p = CharNextA (p))
739 if (*p == '\\')
740 *p = '/';
741
734 strcpy (out_filename, in_filename); 742 strcpy (out_filename, in_filename);
743 filename_to_ansi (new_name, new_name_a);
735 744
736 /* Change the base of the output filename to match the requested name. */ 745 /* Change the base of the output filename to match the requested name. */
737 if ((p = strrchr (out_filename, '/')) == NULL) 746 if ((p = strrchr (out_filename, '/')) == NULL)
738 abort (); 747 abort ();
739 /* The filenames have already been expanded, and will be in Unix 748 /* The filenames have already been expanded, and will be in Unix
740 format, so it is safe to expect an absolute name. */ 749 format, so it is safe to expect an absolute name. */
741 if ((q = strrchr (new_name, '/')) == NULL) 750 if ((q = strrchr (new_name_a, '/')) == NULL)
742 abort (); 751 abort ();
743 strcpy (p, q); 752 strcpy (p, q);
744 753
diff --git a/src/w32.c b/src/w32.c
index e48078aec99..bff0e53e8c8 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -248,7 +248,7 @@ static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
248static int restore_privilege (TOKEN_PRIVILEGES *); 248static int restore_privilege (TOKEN_PRIVILEGES *);
249static BOOL WINAPI revert_to_self (void); 249static BOOL WINAPI revert_to_self (void);
250 250
251extern int sys_access (const char *, int); 251static int sys_access (const char *, int);
252extern void *e_malloc (size_t); 252extern void *e_malloc (size_t);
253extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, 253extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
254 struct timespec *, void *); 254 struct timespec *, void *);
@@ -273,7 +273,8 @@ static BOOL g_b_init_lookup_account_sid;
273static BOOL g_b_init_get_sid_sub_authority; 273static BOOL g_b_init_get_sid_sub_authority;
274static BOOL g_b_init_get_sid_sub_authority_count; 274static BOOL g_b_init_get_sid_sub_authority_count;
275static BOOL g_b_init_get_security_info; 275static BOOL g_b_init_get_security_info;
276static BOOL g_b_init_get_file_security; 276static BOOL g_b_init_get_file_security_w;
277static BOOL g_b_init_get_file_security_a;
277static BOOL g_b_init_get_security_descriptor_owner; 278static BOOL g_b_init_get_security_descriptor_owner;
278static BOOL g_b_init_get_security_descriptor_group; 279static BOOL g_b_init_get_security_descriptor_group;
279static BOOL g_b_init_is_valid_sid; 280static BOOL g_b_init_is_valid_sid;
@@ -292,12 +293,14 @@ static BOOL g_b_init_equal_sid;
292static BOOL g_b_init_copy_sid; 293static BOOL g_b_init_copy_sid;
293static BOOL g_b_init_get_native_system_info; 294static BOOL g_b_init_get_native_system_info;
294static BOOL g_b_init_get_system_times; 295static BOOL g_b_init_get_system_times;
295static BOOL g_b_init_create_symbolic_link; 296static BOOL g_b_init_create_symbolic_link_w;
297static BOOL g_b_init_create_symbolic_link_a;
296static BOOL g_b_init_get_security_descriptor_dacl; 298static BOOL g_b_init_get_security_descriptor_dacl;
297static BOOL g_b_init_convert_sd_to_sddl; 299static BOOL g_b_init_convert_sd_to_sddl;
298static BOOL g_b_init_convert_sddl_to_sd; 300static BOOL g_b_init_convert_sddl_to_sd;
299static BOOL g_b_init_is_valid_security_descriptor; 301static BOOL g_b_init_is_valid_security_descriptor;
300static BOOL g_b_init_set_file_security; 302static BOOL g_b_init_set_file_security_w;
303static BOOL g_b_init_set_file_security_a;
301static BOOL g_b_init_get_adapters_info; 304static BOOL g_b_init_get_adapters_info;
302 305
303/* 306/*
@@ -327,12 +330,8 @@ GetProcessTimes_Proc get_process_times_fn = NULL;
327 330
328#ifdef _UNICODE 331#ifdef _UNICODE
329const char * const LookupAccountSid_Name = "LookupAccountSidW"; 332const char * const LookupAccountSid_Name = "LookupAccountSidW";
330const char * const GetFileSecurity_Name = "GetFileSecurityW";
331const char * const SetFileSecurity_Name = "SetFileSecurityW";
332#else 333#else
333const char * const LookupAccountSid_Name = "LookupAccountSidA"; 334const char * const LookupAccountSid_Name = "LookupAccountSidA";
334const char * const GetFileSecurity_Name = "GetFileSecurityA";
335const char * const SetFileSecurity_Name = "SetFileSecurityA";
336#endif 335#endif
337typedef BOOL (WINAPI * LookupAccountSid_Proc) ( 336typedef BOOL (WINAPI * LookupAccountSid_Proc) (
338 LPCTSTR lpSystemName, 337 LPCTSTR lpSystemName,
@@ -356,14 +355,24 @@ typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
356 PACL *ppDacl, 355 PACL *ppDacl,
357 PACL *ppSacl, 356 PACL *ppSacl,
358 PSECURITY_DESCRIPTOR *ppSecurityDescriptor); 357 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
359typedef BOOL (WINAPI * GetFileSecurity_Proc) ( 358typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
360 LPCTSTR lpFileName, 359 LPCWSTR lpFileName,
361 SECURITY_INFORMATION RequestedInformation, 360 SECURITY_INFORMATION RequestedInformation,
362 PSECURITY_DESCRIPTOR pSecurityDescriptor, 361 PSECURITY_DESCRIPTOR pSecurityDescriptor,
363 DWORD nLength, 362 DWORD nLength,
364 LPDWORD lpnLengthNeeded); 363 LPDWORD lpnLengthNeeded);
365typedef BOOL (WINAPI *SetFileSecurity_Proc) ( 364typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
366 LPCTSTR lpFileName, 365 LPCSTR lpFileName,
366 SECURITY_INFORMATION RequestedInformation,
367 PSECURITY_DESCRIPTOR pSecurityDescriptor,
368 DWORD nLength,
369 LPDWORD lpnLengthNeeded);
370typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
371 LPCWSTR lpFileName,
372 SECURITY_INFORMATION SecurityInformation,
373 PSECURITY_DESCRIPTOR pSecurityDescriptor);
374typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
375 LPCSTR lpFileName,
367 SECURITY_INFORMATION SecurityInformation, 376 SECURITY_INFORMATION SecurityInformation,
368 PSECURITY_DESCRIPTOR pSecurityDescriptor); 377 PSECURITY_DESCRIPTOR pSecurityDescriptor);
369typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( 378typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
@@ -425,9 +434,13 @@ typedef BOOL (WINAPI * GetSystemTimes_Proc) (
425 LPFILETIME lpIdleTime, 434 LPFILETIME lpIdleTime,
426 LPFILETIME lpKernelTime, 435 LPFILETIME lpKernelTime,
427 LPFILETIME lpUserTime); 436 LPFILETIME lpUserTime);
428typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( 437typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
429 LPTSTR lpSymlinkFileName, 438 LPCWSTR lpSymlinkFileName,
430 LPTSTR lpTargetFileName, 439 LPCWSTR lpTargetFileName,
440 DWORD dwFlags);
441typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
442 LPCSTR lpSymlinkFileName,
443 LPCSTR lpTargetFileName,
431 DWORD dwFlags); 444 DWORD dwFlags);
432typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( 445typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
433 LPCTSTR StringSecurityDescriptor, 446 LPCTSTR StringSecurityDescriptor,
@@ -679,64 +692,121 @@ get_security_info (HANDLE handle,
679} 692}
680 693
681static BOOL WINAPI 694static BOOL WINAPI
682get_file_security (LPCTSTR lpFileName, 695get_file_security (const char *lpFileName,
683 SECURITY_INFORMATION RequestedInformation, 696 SECURITY_INFORMATION RequestedInformation,
684 PSECURITY_DESCRIPTOR pSecurityDescriptor, 697 PSECURITY_DESCRIPTOR pSecurityDescriptor,
685 DWORD nLength, 698 DWORD nLength,
686 LPDWORD lpnLengthNeeded) 699 LPDWORD lpnLengthNeeded)
687{ 700{
688 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL; 701 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
702 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
689 HMODULE hm_advapi32 = NULL; 703 HMODULE hm_advapi32 = NULL;
690 if (is_windows_9x () == TRUE) 704 if (is_windows_9x () == TRUE)
691 { 705 {
692 errno = ENOTSUP; 706 errno = ENOTSUP;
693 return FALSE; 707 return FALSE;
694 } 708 }
695 if (g_b_init_get_file_security == 0) 709 if (w32_unicode_filenames)
696 { 710 {
697 g_b_init_get_file_security = 1; 711 wchar_t filename_w[MAX_PATH];
698 hm_advapi32 = LoadLibrary ("Advapi32.dll"); 712
699 s_pfn_Get_File_Security = 713 if (g_b_init_get_file_security_w == 0)
700 (GetFileSecurity_Proc) GetProcAddress ( 714 {
701 hm_advapi32, GetFileSecurity_Name); 715 g_b_init_get_file_security_w = 1;
716 hm_advapi32 = LoadLibrary ("Advapi32.dll");
717 s_pfn_Get_File_SecurityW =
718 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
719 "GetFileSecurityW");
720 }
721 if (s_pfn_Get_File_SecurityW == NULL)
722 {
723 errno = ENOTSUP;
724 return FALSE;
725 }
726 filename_to_utf16 (lpFileName, filename_w);
727 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
728 pSecurityDescriptor, nLength,
729 lpnLengthNeeded));
702 } 730 }
703 if (s_pfn_Get_File_Security == NULL) 731 else
704 { 732 {
705 errno = ENOTSUP; 733 char filename_a[MAX_PATH];
706 return FALSE; 734
735 if (g_b_init_get_file_security_a == 0)
736 {
737 g_b_init_get_file_security_a = 1;
738 hm_advapi32 = LoadLibrary ("Advapi32.dll");
739 s_pfn_Get_File_SecurityA =
740 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
741 "GetFileSecurityA");
742 }
743 if (s_pfn_Get_File_SecurityA == NULL)
744 {
745 errno = ENOTSUP;
746 return FALSE;
747 }
748 filename_to_ansi (lpFileName, filename_a);
749 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
750 pSecurityDescriptor, nLength,
751 lpnLengthNeeded));
707 } 752 }
708 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
709 pSecurityDescriptor, nLength,
710 lpnLengthNeeded));
711} 753}
712 754
713static BOOL WINAPI 755static BOOL WINAPI
714set_file_security (LPCTSTR lpFileName, 756set_file_security (const char *lpFileName,
715 SECURITY_INFORMATION SecurityInformation, 757 SECURITY_INFORMATION SecurityInformation,
716 PSECURITY_DESCRIPTOR pSecurityDescriptor) 758 PSECURITY_DESCRIPTOR pSecurityDescriptor)
717{ 759{
718 static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL; 760 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
761 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
719 HMODULE hm_advapi32 = NULL; 762 HMODULE hm_advapi32 = NULL;
720 if (is_windows_9x () == TRUE) 763 if (is_windows_9x () == TRUE)
721 { 764 {
722 errno = ENOTSUP; 765 errno = ENOTSUP;
723 return FALSE; 766 return FALSE;
724 } 767 }
725 if (g_b_init_set_file_security == 0) 768 if (w32_unicode_filenames)
726 { 769 {
727 g_b_init_set_file_security = 1; 770 wchar_t filename_w[MAX_PATH];
728 hm_advapi32 = LoadLibrary ("Advapi32.dll"); 771
729 s_pfn_Set_File_Security = 772 if (g_b_init_set_file_security_w == 0)
730 (SetFileSecurity_Proc) GetProcAddress ( 773 {
731 hm_advapi32, SetFileSecurity_Name); 774 g_b_init_set_file_security_w = 1;
775 hm_advapi32 = LoadLibrary ("Advapi32.dll");
776 s_pfn_Set_File_SecurityW =
777 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
778 "SetFileSecurityW");
779 }
780 if (s_pfn_Set_File_SecurityW == NULL)
781 {
782 errno = ENOTSUP;
783 return FALSE;
784 }
785 filename_to_utf16 (lpFileName, filename_w);
786 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
787 pSecurityDescriptor));
732 } 788 }
733 if (s_pfn_Set_File_Security == NULL) 789 else
734 { 790 {
735 errno = ENOTSUP; 791 char filename_a[MAX_PATH];
736 return FALSE; 792
793 if (g_b_init_set_file_security_a == 0)
794 {
795 g_b_init_set_file_security_a = 1;
796 hm_advapi32 = LoadLibrary ("Advapi32.dll");
797 s_pfn_Set_File_SecurityA =
798 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
799 "SetFileSecurityA");
800 }
801 if (s_pfn_Set_File_SecurityA == NULL)
802 {
803 errno = ENOTSUP;
804 return FALSE;
805 }
806 filename_to_ansi (lpFileName, filename_a);
807 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
808 pSecurityDescriptor));
737 } 809 }
738 return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
739 pSecurityDescriptor));
740} 810}
741 811
742static BOOL WINAPI 812static BOOL WINAPI
@@ -973,11 +1043,12 @@ get_system_times (LPFILETIME lpIdleTime,
973} 1043}
974 1044
975static BOOLEAN WINAPI 1045static BOOLEAN WINAPI
976create_symbolic_link (LPTSTR lpSymlinkFilename, 1046create_symbolic_link (LPCSTR lpSymlinkFilename,
977 LPTSTR lpTargetFileName, 1047 LPCSTR lpTargetFileName,
978 DWORD dwFlags) 1048 DWORD dwFlags)
979{ 1049{
980 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL; 1050 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1051 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
981 BOOLEAN retval; 1052 BOOLEAN retval;
982 1053
983 if (is_windows_9x () == TRUE) 1054 if (is_windows_9x () == TRUE)
@@ -985,39 +1056,74 @@ create_symbolic_link (LPTSTR lpSymlinkFilename,
985 errno = ENOSYS; 1056 errno = ENOSYS;
986 return 0; 1057 return 0;
987 } 1058 }
988 if (g_b_init_create_symbolic_link == 0) 1059 if (w32_unicode_filenames)
989 { 1060 {
990 g_b_init_create_symbolic_link = 1; 1061 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
991#ifdef _UNICODE 1062
992 s_pfn_Create_Symbolic_Link = 1063 if (g_b_init_create_symbolic_link_w == 0)
993 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), 1064 {
994 "CreateSymbolicLinkW"); 1065 g_b_init_create_symbolic_link_w = 1;
995#else 1066 s_pfn_Create_Symbolic_LinkW =
996 s_pfn_Create_Symbolic_Link = 1067 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
997 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"), 1068 "CreateSymbolicLinkW");
998 "CreateSymbolicLinkA"); 1069 }
999#endif 1070 if (s_pfn_Create_Symbolic_LinkW == NULL)
1071 {
1072 errno = ENOSYS;
1073 return 0;
1074 }
1075
1076 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1077 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1078 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1079 /* If we were denied creation of the symlink, try again after
1080 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1081 if (!retval)
1082 {
1083 TOKEN_PRIVILEGES priv_current;
1084
1085 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1086 &priv_current))
1087 {
1088 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1089 restore_privilege (&priv_current);
1090 revert_to_self ();
1091 }
1092 }
1000 } 1093 }
1001 if (s_pfn_Create_Symbolic_Link == NULL) 1094 else
1002 { 1095 {
1003 errno = ENOSYS; 1096 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1004 return 0;
1005 }
1006 1097
1007 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName, 1098 if (g_b_init_create_symbolic_link_a == 0)
1008 dwFlags); 1099 {
1009 /* If we were denied creation of the symlink, try again after 1100 g_b_init_create_symbolic_link_a = 1;
1010 enabling the SeCreateSymbolicLinkPrivilege for our process. */ 1101 s_pfn_Create_Symbolic_LinkA =
1011 if (!retval) 1102 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1012 { 1103 "CreateSymbolicLinkA");
1013 TOKEN_PRIVILEGES priv_current; 1104 }
1105 if (s_pfn_Create_Symbolic_LinkA == NULL)
1106 {
1107 errno = ENOSYS;
1108 return 0;
1109 }
1014 1110
1015 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current)) 1111 filename_to_ansi (lpSymlinkFilename, symfn_a);
1112 filename_to_ansi (lpTargetFileName, tgtfn_a);
1113 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1114 /* If we were denied creation of the symlink, try again after
1115 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1116 if (!retval)
1016 { 1117 {
1017 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName, 1118 TOKEN_PRIVILEGES priv_current;
1018 dwFlags); 1119
1019 restore_privilege (&priv_current); 1120 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1020 revert_to_self (); 1121 &priv_current))
1122 {
1123 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1124 restore_privilege (&priv_current);
1125 revert_to_self ();
1126 }
1021 } 1127 }
1022 } 1128 }
1023 return retval; 1129 return retval;
@@ -1182,7 +1288,297 @@ w32_valid_pointer_p (void *p, int size)
1182 return -1; 1288 return -1;
1183} 1289}
1184 1290
1185static char startup_dir[MAXPATHLEN]; 1291
1292
1293/* Here's an overview of how the Windows build supports file names
1294 that cannot be encoded by the current system codepage.
1295
1296 From the POV of Lisp and layers of C code above the functions here,
1297 Emacs on Windows pretends that its file names are encoded in UTF-8;
1298 see encode_file and decode_file on coding.c. Any file name that is
1299 passed as a unibyte string to C functions defined here is assumed
1300 to be in UTF-8 encoding. Any file name returned by functions
1301 defined here must be in UTF-8 encoding, with only a few exceptions
1302 reserved for a couple of special cases. (Be sure to use
1303 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1304 as they can be much longer than MAX_PATH!)
1305
1306 The UTF-8 encoded file names cannot be passed to system APIs, as
1307 Windows does not support that. Therefore, they are converted
1308 either to UTF-16 or to the ANSI codepage, depending on the value of
1309 w32-unicode-filenames, before calling any system APIs or CRT library
1310 functions. The default value of that variable is determined by the
1311 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1312 user can change that default (although I don't see why would she
1313 want to).
1314
1315 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1316 filename_from_utf16, and filename_from_ansi, are the workhorses of
1317 these conversions. They rely on Windows native APIs
1318 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1319 functions from coding.c here, because they allocate memory, which
1320 is a bad idea on the level of libc, which is what the functions
1321 here emulate. (If you worry about performance due to constant
1322 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1323 it was measured to take only a few microseconds on a not-so-fast
1324 machine, and second, that's exactly what the ANSI APIs we used
1325 before do anyway, because they are just thin wrappers around the
1326 Unicode APIs.)
1327
1328 The variables file-name-coding-system and default-file-name-coding-system
1329 still exist, but are actually used only when a file name needs to
1330 be converted to the ANSI codepage. This happens all the time when
1331 w32-unicode-filenames is nil, but can also happen from time to time
1332 when it is t. Otherwise, these variables have no effect on file-name
1333 encoding when w32-unicode-filenames is t; this is similar to
1334 selection-coding-system.
1335
1336 This arrangement works very well, but it has a few gotchas and
1337 limitations:
1338
1339 . Lisp code that encodes or decodes file names manually should
1340 normally use 'utf-8' as the coding-system on Windows,
1341 disregarding file-name-coding-system. This is a somewhat
1342 unpleasant consequence, but it cannot be avoided. Fortunately,
1343 very few Lisp packages need to do that.
1344
1345 More generally, passing to library functions (e.g., fopen or
1346 opendir) file names already encoded in the ANSI codepage is
1347 explictly *verboten*, as all those functions, as shadowed and
1348 emulated here, assume they will receive UTF-8 encoded file names.
1349
1350 For the same reasons, no CRT function or Win32 API can be called
1351 directly in Emacs sources, without either converting the file
1352 name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
1353 through some shadowing function defined here.
1354
1355 . Environment variables stored in Vprocess_environment are encoded
1356 in the ANSI codepage, so if getenv/egetenv is used for a variable
1357 whose value is a file name or a list of directories, it needs to
1358 be converted to UTF-8, before it is used as argument to functions
1359 or decoded into a Lisp string.
1360
1361 . File names passed to external libraries, like the image libraries
1362 and GnuTLS, need special handling. These libraries generally
1363 don't support UTF-16 or UTF-8 file names, so they must get file
1364 names encoded in the ANSI codepage. To facilitate using these
1365 libraries with file names that are not encodable in the ANSI
1366 codepage, use the function ansi_encode_filename, which will try
1367 to use the short 8+3 alias of a file name if that file name is
1368 not encodable in the ANSI codepage. See image.c and gnutls.c for
1369 examples of how this should be done.
1370
1371 . Running subprocesses in non-ASCII directories and with non-ASCII
1372 file arguments is limited to the current codepage (even though
1373 Emacs is perfectly capable of finding an executable program file
1374 even in a directory whose name cannot be encoded in the curreent
1375 codepage). This is because the command-line arguments are
1376 encoded _before_ they get to the w32-specific level, and the
1377 encoding is not known in advance (it doesn't have to be the
1378 current ANSI codepage), so w32proc.c functions cannot re-encode
1379 them in UTF-16. This should be fixed, but will also require
1380 changes in cmdproxy. The current limitation is not terribly bad
1381 anyway, since very few, if any, Windows console programs that are
1382 likely to be invoked by Emacs support UTF-16 encoded command
1383 lines.
1384
1385 . For similar reasons, server.el and emacsclient are also limited
1386 to the current ANSI codepage for now.
1387
1388 . Emacs itself can only handle command-line arguments encoded in
1389 the current codepage.
1390
1391 . Turning on w32-unicode-filename on Windows 9X (if it at all
1392 works) requires UNICOWS.DLL, which is currently loaded only in a
1393 GUI session. */
1394
1395
1396
1397/* Converting file names from UTF-8 to either UTF-16 or the ANSI
1398 codepage defined by file-name-coding-system. */
1399
1400/* Current codepage for encoding file names. */
1401static int file_name_codepage;
1402
1403/* Produce a Windows ANSI codepage suitable for encoding file names.
1404 Return the information about that codepage in CP_INFO. */
1405static int
1406codepage_for_filenames (CPINFO *cp_info)
1407{
1408 /* A simple cache to avoid calling GetCPInfo every time we need to
1409 encode/decode a file name. The file-name encoding is not
1410 supposed to be changed too frequently, if ever. */
1411 static Lisp_Object last_file_name_encoding;
1412 static CPINFO cp;
1413 Lisp_Object current_encoding;
1414
1415 current_encoding = Vfile_name_coding_system;
1416 if (NILP (current_encoding))
1417 current_encoding = Vdefault_file_name_coding_system;
1418
1419 if (!EQ (last_file_name_encoding, current_encoding))
1420 {
1421 /* Default to the current ANSI codepage. */
1422 file_name_codepage = w32_ansi_code_page;
1423
1424 if (NILP (current_encoding))
1425 {
1426 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1427 char *cp = NULL, *end;
1428 int cpnum;
1429
1430 if (strncmp (cpname, "cp", 2) == 0)
1431 cp = cpname + 2;
1432 else if (strncmp (cpname, "windows-", 8) == 0)
1433 cp = cpname + 8;
1434
1435 if (cp)
1436 {
1437 end = cp;
1438 cpnum = strtol (cp, &end, 10);
1439 if (cpnum && *end == '\0' && end - cp >= 2)
1440 file_name_codepage = cpnum;
1441 }
1442 }
1443
1444 if (!file_name_codepage)
1445 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1446
1447 if (!GetCPInfo (file_name_codepage, &cp))
1448 {
1449 file_name_codepage = CP_ACP;
1450 if (!GetCPInfo (file_name_codepage, &cp))
1451 emacs_abort ();
1452 }
1453 }
1454 if (cp_info)
1455 *cp_info = cp;
1456
1457 return file_name_codepage;
1458}
1459
1460int
1461filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1462{
1463 int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1464 fn_out, MAX_PATH);
1465
1466 if (!result)
1467 {
1468 DWORD err = GetLastError ();
1469
1470 switch (err)
1471 {
1472 case ERROR_INVALID_FLAGS:
1473 case ERROR_INVALID_PARAMETER:
1474 errno = EINVAL;
1475 break;
1476 case ERROR_INSUFFICIENT_BUFFER:
1477 case ERROR_NO_UNICODE_TRANSLATION:
1478 default:
1479 errno = ENOENT;
1480 break;
1481 }
1482 return -1;
1483 }
1484 return 0;
1485}
1486
1487int
1488filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1489{
1490 int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1491 fn_out, MAX_UTF8_PATH, NULL, NULL);
1492
1493 if (!result)
1494 {
1495 DWORD err = GetLastError ();
1496
1497 switch (err)
1498 {
1499 case ERROR_INVALID_FLAGS:
1500 case ERROR_INVALID_PARAMETER:
1501 errno = EINVAL;
1502 break;
1503 case ERROR_INSUFFICIENT_BUFFER:
1504 case ERROR_NO_UNICODE_TRANSLATION:
1505 default:
1506 errno = ENOENT;
1507 break;
1508 }
1509 return -1;
1510 }
1511 return 0;
1512}
1513
1514int
1515filename_to_ansi (const char *fn_in, char *fn_out)
1516{
1517 wchar_t fn_utf16[MAX_PATH];
1518
1519 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1520 {
1521 int result;
1522 int codepage = codepage_for_filenames (NULL);
1523
1524 result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
1525 fn_out, MAX_PATH, NULL, NULL);
1526 if (!result)
1527 {
1528 DWORD err = GetLastError ();
1529
1530 switch (err)
1531 {
1532 case ERROR_INVALID_FLAGS:
1533 case ERROR_INVALID_PARAMETER:
1534 errno = EINVAL;
1535 break;
1536 case ERROR_INSUFFICIENT_BUFFER:
1537 case ERROR_NO_UNICODE_TRANSLATION:
1538 default:
1539 errno = ENOENT;
1540 break;
1541 }
1542 return -1;
1543 }
1544 return 0;
1545 }
1546 return -1;
1547}
1548
1549int
1550filename_from_ansi (const char *fn_in, char *fn_out)
1551{
1552 wchar_t fn_utf16[MAX_PATH];
1553 int codepage = codepage_for_filenames (NULL);
1554 int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1555 fn_utf16, MAX_PATH);
1556
1557 if (!result)
1558 {
1559 DWORD err = GetLastError ();
1560
1561 switch (err)
1562 {
1563 case ERROR_INVALID_FLAGS:
1564 case ERROR_INVALID_PARAMETER:
1565 errno = EINVAL;
1566 break;
1567 case ERROR_INSUFFICIENT_BUFFER:
1568 case ERROR_NO_UNICODE_TRANSLATION:
1569 default:
1570 errno = ENOENT;
1571 break;
1572 }
1573 return -1;
1574 }
1575 return filename_from_utf16 (fn_utf16, fn_out);
1576}
1577
1578
1579
1580/* The directory where we started, in UTF-8. */
1581static char startup_dir[MAX_UTF8_PATH];
1186 1582
1187/* Get the current working directory. */ 1583/* Get the current working directory. */
1188char * 1584char *
@@ -1374,8 +1770,8 @@ getloadavg (double loadavg[], int nelem)
1374static char dflt_passwd_name[PASSWD_FIELD_SIZE]; 1770static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1375static char dflt_passwd_passwd[PASSWD_FIELD_SIZE]; 1771static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1376static char dflt_passwd_gecos[PASSWD_FIELD_SIZE]; 1772static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1377static char dflt_passwd_dir[PASSWD_FIELD_SIZE]; 1773static char dflt_passwd_dir[MAX_UTF8_PATH];
1378static char dflt_passwd_shell[PASSWD_FIELD_SIZE]; 1774static char dflt_passwd_shell[MAX_UTF8_PATH];
1379 1775
1380static struct passwd dflt_passwd = 1776static struct passwd dflt_passwd =
1381{ 1777{
@@ -1556,15 +1952,32 @@ init_user_info (void)
1556 } 1952 }
1557 dflt_group.gr_gid = dflt_passwd.pw_gid; 1953 dflt_group.gr_gid = dflt_passwd.pw_gid;
1558 1954
1559 /* Ensure HOME and SHELL are defined. */
1560 if (getenv ("HOME") == NULL)
1561 emacs_abort ();
1562 if (getenv ("SHELL") == NULL)
1563 emacs_abort ();
1564
1565 /* Set dir and shell from environment variables. */ 1955 /* Set dir and shell from environment variables. */
1566 strcpy (dflt_passwd.pw_dir, getenv ("HOME")); 1956 if (w32_unicode_filenames)
1567 strcpy (dflt_passwd.pw_shell, getenv ("SHELL")); 1957 {
1958 wchar_t *home = _wgetenv (L"HOME");
1959 wchar_t *shell = _wgetenv (L"SHELL");
1960
1961 /* Ensure HOME and SHELL are defined. */
1962 if (home == NULL)
1963 emacs_abort ();
1964 if (shell == NULL)
1965 emacs_abort ();
1966 filename_from_utf16 (home, dflt_passwd.pw_dir);
1967 filename_from_utf16 (shell, dflt_passwd.pw_shell);
1968 }
1969 else
1970 {
1971 char *home = getenv ("HOME");
1972 char *shell = getenv ("SHELL");
1973
1974 if (home == NULL)
1975 emacs_abort ();
1976 if (shell == NULL)
1977 emacs_abort ();
1978 filename_from_ansi (home, dflt_passwd.pw_dir);
1979 filename_from_ansi (shell, dflt_passwd.pw_shell);
1980 }
1568 1981
1569 xfree (buf); 1982 xfree (buf);
1570 if (token) 1983 if (token)
@@ -1584,93 +1997,32 @@ srandom (int seed)
1584 srand (seed); 1997 srand (seed);
1585} 1998}
1586 1999
1587/* Current codepage for encoding file names. */
1588static int file_name_codepage;
1589
1590/* Return the maximum length in bytes of a multibyte character 2000/* Return the maximum length in bytes of a multibyte character
1591 sequence encoded in the current ANSI codepage. This is required to 2001 sequence encoded in the current ANSI codepage. This is required to
1592 correctly walk the encoded file names one character at a time. */ 2002 correctly walk the encoded file names one character at a time. */
1593static int 2003static int
1594max_filename_mbslen (void) 2004max_filename_mbslen (void)
1595{ 2005{
1596 /* A simple cache to avoid calling GetCPInfo every time we need to 2006 CPINFO cp_info;
1597 normalize a file name. The file-name encoding is not supposed to
1598 be changed too frequently, if ever. */
1599 static Lisp_Object last_file_name_encoding;
1600 static int last_max_mbslen;
1601 Lisp_Object current_encoding;
1602 2007
1603 current_encoding = Vfile_name_coding_system; 2008 codepage_for_filenames (&cp_info);
1604 if (NILP (current_encoding)) 2009 return cp_info.MaxCharSize;
1605 current_encoding = Vdefault_file_name_coding_system;
1606
1607 if (!EQ (last_file_name_encoding, current_encoding))
1608 {
1609 CPINFO cp_info;
1610
1611 last_file_name_encoding = current_encoding;
1612 /* Default to the current ANSI codepage. */
1613 file_name_codepage = w32_ansi_code_page;
1614 if (!NILP (current_encoding))
1615 {
1616 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1617 char *cp = NULL, *end;
1618 int cpnum;
1619
1620 if (strncmp (cpname, "cp", 2) == 0)
1621 cp = cpname + 2;
1622 else if (strncmp (cpname, "windows-", 8) == 0)
1623 cp = cpname + 8;
1624
1625 if (cp)
1626 {
1627 end = cp;
1628 cpnum = strtol (cp, &end, 10);
1629 if (cpnum && *end == '\0' && end - cp >= 2)
1630 file_name_codepage = cpnum;
1631 }
1632 }
1633
1634 if (!file_name_codepage)
1635 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1636
1637 if (!GetCPInfo (file_name_codepage, &cp_info))
1638 {
1639 file_name_codepage = CP_ACP;
1640 if (!GetCPInfo (file_name_codepage, &cp_info))
1641 emacs_abort ();
1642 }
1643 last_max_mbslen = cp_info.MaxCharSize;
1644 }
1645
1646 return last_max_mbslen;
1647} 2010}
1648 2011
1649/* Normalize filename by converting all path separators to 2012/* Normalize filename by converting in-place all of its path
1650 the specified separator. Also conditionally convert upper 2013 separators to the separator specified by PATH_SEP. */
1651 case path name components to lower case. */
1652 2014
1653static void 2015static void
1654normalize_filename (register char *fp, char path_sep, int multibyte) 2016normalize_filename (register char *fp, char path_sep)
1655{ 2017{
1656 char sep; 2018 char *p2;
1657 char *elem, *p2;
1658 int dbcs_p = max_filename_mbslen () > 1;
1659
1660 /* Multibyte file names are in the Emacs internal representation, so
1661 we can traverse them by bytes with no problems. */
1662 if (multibyte)
1663 dbcs_p = 0;
1664 2019
1665 /* Always lower-case drive letters a-z, even if the filesystem 2020 /* Always lower-case drive letters a-z, even if the filesystem
1666 preserves case in filenames. 2021 preserves case in filenames.
1667 This is so filenames can be compared by string comparison 2022 This is so filenames can be compared by string comparison
1668 functions that are case-sensitive. Even case-preserving filesystems 2023 functions that are case-sensitive. Even case-preserving filesystems
1669 do not distinguish case in drive letters. */ 2024 do not distinguish case in drive letters. */
1670 if (dbcs_p) 2025 p2 = fp + 1;
1671 p2 = CharNextExA (file_name_codepage, fp, 0);
1672 else
1673 p2 = fp + 1;
1674 2026
1675 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z') 2027 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1676 { 2028 {
@@ -1678,68 +2030,26 @@ normalize_filename (register char *fp, char path_sep, int multibyte)
1678 fp += 2; 2030 fp += 2;
1679 } 2031 }
1680 2032
1681 if (multibyte || NILP (Vw32_downcase_file_names)) 2033 while (*fp)
1682 { 2034 {
1683 while (*fp) 2035 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
1684 { 2036 *fp = path_sep;
1685 if (*fp == '/' || *fp == '\\') 2037 fp++;
1686 *fp = path_sep;
1687 if (!dbcs_p)
1688 fp++;
1689 else
1690 fp = CharNextExA (file_name_codepage, fp, 0);
1691 }
1692 return;
1693 } 2038 }
1694
1695 sep = path_sep; /* convert to this path separator */
1696 elem = fp; /* start of current path element */
1697
1698 do {
1699 if (*fp >= 'a' && *fp <= 'z')
1700 elem = 0; /* don't convert this element */
1701
1702 if (*fp == 0 || *fp == ':')
1703 {
1704 sep = *fp; /* restore current separator (or 0) */
1705 *fp = '/'; /* after conversion of this element */
1706 }
1707
1708 if (*fp == '/' || *fp == '\\')
1709 {
1710 if (elem && elem != fp)
1711 {
1712 *fp = 0; /* temporary end of string */
1713 _mbslwr (elem); /* while we convert to lower case */
1714 }
1715 *fp = sep; /* convert (or restore) path separator */
1716 elem = fp + 1; /* next element starts after separator */
1717 sep = path_sep;
1718 }
1719 if (*fp)
1720 {
1721 if (!dbcs_p)
1722 fp++;
1723 else
1724 fp = CharNextExA (file_name_codepage, fp, 0);
1725 }
1726 } while (*fp);
1727} 2039}
1728 2040
1729/* Destructively turn backslashes into slashes. MULTIBYTE non-zero 2041/* Destructively turn backslashes into slashes. */
1730 means the file name is a multibyte string in Emacs's internal
1731 representation. */
1732void 2042void
1733dostounix_filename (register char *p, int multibyte) 2043dostounix_filename (register char *p)
1734{ 2044{
1735 normalize_filename (p, '/', multibyte); 2045 normalize_filename (p, '/');
1736} 2046}
1737 2047
1738/* Destructively turn slashes into backslashes. */ 2048/* Destructively turn slashes into backslashes. */
1739void 2049void
1740unixtodos_filename (register char *p) 2050unixtodos_filename (register char *p)
1741{ 2051{
1742 normalize_filename (p, '\\', 0); 2052 normalize_filename (p, '\\');
1743} 2053}
1744 2054
1745/* Remove all CR's that are followed by a LF. 2055/* Remove all CR's that are followed by a LF.
@@ -1772,9 +2082,9 @@ crlf_to_lf (register int n, register unsigned char *buf)
1772/* Parse the root part of file name, if present. Return length and 2082/* Parse the root part of file name, if present. Return length and
1773 optionally store pointer to char after root. */ 2083 optionally store pointer to char after root. */
1774static int 2084static int
1775parse_root (char * name, char ** pPath) 2085parse_root (const char * name, const char ** pPath)
1776{ 2086{
1777 char * start = name; 2087 const char * start = name;
1778 2088
1779 if (name == NULL) 2089 if (name == NULL)
1780 return 0; 2090 return 0;
@@ -1790,17 +2100,13 @@ parse_root (char * name, char ** pPath)
1790 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) 2100 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1791 { 2101 {
1792 int slashes = 2; 2102 int slashes = 2;
1793 int dbcs_p = max_filename_mbslen () > 1;
1794 2103
1795 name += 2; 2104 name += 2;
1796 do 2105 do
1797 { 2106 {
1798 if (IS_DIRECTORY_SEP (*name) && --slashes == 0) 2107 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1799 break; 2108 break;
1800 if (dbcs_p) 2109 name++;
1801 name = CharNextExA (file_name_codepage, name, 0);
1802 else
1803 name++;
1804 } 2110 }
1805 while ( *name ); 2111 while ( *name );
1806 if (IS_DIRECTORY_SEP (name[0])) 2112 if (IS_DIRECTORY_SEP (name[0]))
@@ -1817,23 +2123,63 @@ parse_root (char * name, char ** pPath)
1817static int 2123static int
1818get_long_basename (char * name, char * buf, int size) 2124get_long_basename (char * name, char * buf, int size)
1819{ 2125{
1820 WIN32_FIND_DATA find_data; 2126 HANDLE dir_handle = INVALID_HANDLE_VALUE;
1821 HANDLE dir_handle; 2127 char fname_utf8[MAX_UTF8_PATH];
1822 int len = 0; 2128 int len = 0;
2129 int cstatus = -1;
1823 2130
1824 /* must be valid filename, no wild cards or other invalid characters */ 2131 /* Must be valid filename, no wild cards or other invalid characters. */
1825 if (_mbspbrk (name, "*?|<>\"")) 2132 if (strpbrk (name, "*?|<>\""))
1826 return 0; 2133 return 0;
1827 2134
1828 dir_handle = FindFirstFile (name, &find_data); 2135 if (w32_unicode_filenames)
1829 if (dir_handle != INVALID_HANDLE_VALUE) 2136 {
2137 wchar_t fname_utf16[MAX_PATH];
2138 WIN32_FIND_DATAW find_data_wide;
2139
2140 filename_to_utf16 (name, fname_utf16);
2141 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2142 if (dir_handle != INVALID_HANDLE_VALUE)
2143 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2144 }
2145 else
1830 { 2146 {
1831 if ((len = strlen (find_data.cFileName)) < size) 2147 char fname_ansi[MAX_PATH];
1832 memcpy (buf, find_data.cFileName, len + 1); 2148 WIN32_FIND_DATAA find_data_ansi;
2149
2150 filename_to_ansi (name, fname_ansi);
2151 /* If the ANSI name includes ? characters, it is not encodable
2152 in the ANSI codepage. In that case, we deliver the question
2153 marks to the caller; calling FindFirstFileA in this case
2154 could return some unrelated file name in the same
2155 directory. */
2156 if (_mbspbrk (fname_ansi, "?"))
2157 {
2158 /* Find the basename of fname_ansi. */
2159 char *p = strrchr (fname_ansi, '\\');
2160
2161 if (!p)
2162 p = fname_ansi;
2163 else
2164 p++;
2165 cstatus = filename_from_ansi (p, fname_utf8);
2166 }
1833 else 2167 else
1834 len = 0; 2168 {
1835 FindClose (dir_handle); 2169 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2170 if (dir_handle != INVALID_HANDLE_VALUE)
2171 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2172 }
1836 } 2173 }
2174
2175 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2176 memcpy (buf, fname_utf8, len + 1);
2177 else
2178 len = 0;
2179
2180 if (dir_handle != INVALID_HANDLE_VALUE)
2181 FindClose (dir_handle);
2182
1837 return len; 2183 return len;
1838} 2184}
1839 2185
@@ -1843,12 +2189,12 @@ w32_get_long_filename (char * name, char * buf, int size)
1843{ 2189{
1844 char * o = buf; 2190 char * o = buf;
1845 char * p; 2191 char * p;
1846 char * q; 2192 const char * q;
1847 char full[ MAX_PATH ]; 2193 char full[ MAX_UTF8_PATH ];
1848 int len; 2194 int len;
1849 2195
1850 len = strlen (name); 2196 len = strlen (name);
1851 if (len >= MAX_PATH) 2197 if (len >= MAX_UTF8_PATH)
1852 return FALSE; 2198 return FALSE;
1853 2199
1854 /* Use local copy for destructive modification. */ 2200 /* Use local copy for destructive modification. */
@@ -1856,7 +2202,7 @@ w32_get_long_filename (char * name, char * buf, int size)
1856 unixtodos_filename (full); 2202 unixtodos_filename (full);
1857 2203
1858 /* Copy root part verbatim. */ 2204 /* Copy root part verbatim. */
1859 len = parse_root (full, &p); 2205 len = parse_root (full, (const char **)&p);
1860 memcpy (o, full, len); 2206 memcpy (o, full, len);
1861 o += len; 2207 o += len;
1862 *o = '\0'; 2208 *o = '\0';
@@ -1865,7 +2211,7 @@ w32_get_long_filename (char * name, char * buf, int size)
1865 while (p != NULL && *p) 2211 while (p != NULL && *p)
1866 { 2212 {
1867 q = p; 2213 q = p;
1868 p = _mbschr (q, '\\'); 2214 p = strchr (q, '\\');
1869 if (p) *p = '\0'; 2215 if (p) *p = '\0';
1870 len = get_long_basename (full, o, size); 2216 len = get_long_basename (full, o, size);
1871 if (len > 0) 2217 if (len > 0)
@@ -1889,6 +2235,59 @@ w32_get_long_filename (char * name, char * buf, int size)
1889 return TRUE; 2235 return TRUE;
1890} 2236}
1891 2237
2238unsigned int
2239w32_get_short_filename (char * name, char * buf, int size)
2240{
2241 if (w32_unicode_filenames)
2242 {
2243 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2244 unsigned int retval;
2245
2246 filename_to_utf16 (name, name_utf16);
2247 retval = GetShortPathNameW (name_utf16, short_name, size);
2248 if (retval && retval < size)
2249 filename_from_utf16 (short_name, buf);
2250 return retval;
2251 }
2252 else
2253 {
2254 char name_ansi[MAX_PATH];
2255
2256 filename_to_ansi (name, name_ansi);
2257 return GetShortPathNameA (name_ansi, buf, size);
2258 }
2259}
2260
2261/* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2262 MS-Windows ANSI codepage. If FILENAME includes characters not
2263 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2264 if it exists. This is needed because the w32 build wants to
2265 support file names outside of the system locale, but image
2266 libraries typically don't support wide (a.k.a. "Unicode") APIs
2267 required for that. */
2268
2269Lisp_Object
2270ansi_encode_filename (Lisp_Object filename)
2271{
2272 Lisp_Object encoded_filename;
2273 char fname[MAX_PATH];
2274
2275 filename_to_ansi (SSDATA (filename), fname);
2276 if (_mbspbrk (fname, "?"))
2277 {
2278 char shortname[MAX_PATH];
2279
2280 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2281 {
2282 dostounix_filename (shortname);
2283 encoded_filename = build_string (shortname);
2284 }
2285 }
2286 else
2287 encoded_filename = build_unibyte_string (fname);
2288 return encoded_filename;
2289}
2290
1892static int 2291static int
1893is_unc_volume (const char *filename) 2292is_unc_volume (const char *filename)
1894{ 2293{
@@ -1897,7 +2296,7 @@ is_unc_volume (const char *filename)
1897 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2]) 2296 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1898 return 0; 2297 return 0;
1899 2298
1900 if (_mbspbrk (ptr + 2, "*?|<>\"\\/")) 2299 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
1901 return 0; 2300 return 0;
1902 2301
1903 return 1; 2302 return 1;
@@ -1997,8 +2396,8 @@ w32_get_resource (char *key, LPDWORD lpdwtype)
1997 return (NULL); 2396 return (NULL);
1998} 2397}
1999 2398
2000char *get_emacs_configuration (void); 2399/* The argv[] array holds ANSI-encoded strings, and so this function
2001 2400 works with ANS_encoded strings. */
2002void 2401void
2003init_environment (char ** argv) 2402init_environment (char ** argv)
2004{ 2403{
@@ -2010,6 +2409,13 @@ init_environment (char ** argv)
2010 2409
2011 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]); 2410 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2012 2411
2412 /* Implementation note: This function explicitly works with ANSI
2413 file names, not with UTF-8 encoded file names. This is because
2414 this function pushes variables into the Emacs's environment, and
2415 the environment variables are always assumed to be in the
2416 locale-specific encoding. Do NOT call any functions that accept
2417 UTF-8 file names from this function! */
2418
2013 /* Make sure they have a usable $TMPDIR. Many Emacs functions use 2419 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2014 temporary files and assume "/tmp" if $TMPDIR is unset, which 2420 temporary files and assume "/tmp" if $TMPDIR is unset, which
2015 will break on DOS/Windows. Refuse to work if we cannot find 2421 will break on DOS/Windows. Refuse to work if we cannot find
@@ -2025,8 +2431,8 @@ init_environment (char ** argv)
2025 The only way to be really sure is to actually create a file and 2431 The only way to be really sure is to actually create a file and
2026 see if it succeeds. But I think that's too much to ask. */ 2432 see if it succeeds. But I think that's too much to ask. */
2027 2433
2028 /* MSVCRT's _access crashes with D_OK. */ 2434 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2029 if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0) 2435 if (tmp && sys_access (tmp, D_OK) == 0)
2030 { 2436 {
2031 char * var = alloca (strlen (tmp) + 8); 2437 char * var = alloca (strlen (tmp) + 8);
2032 sprintf (var, "TMPDIR=%s", tmp); 2438 sprintf (var, "TMPDIR=%s", tmp);
@@ -2088,7 +2494,7 @@ init_environment (char ** argv)
2088 /* For backwards compatibility, check if a .emacs file exists in C:/ 2494 /* For backwards compatibility, check if a .emacs file exists in C:/
2089 If not, then we can try to default to the appdata directory under the 2495 If not, then we can try to default to the appdata directory under the
2090 user's profile, which is more likely to be writable. */ 2496 user's profile, which is more likely to be writable. */
2091 if (faccessat (AT_FDCWD, "C:/.emacs", F_OK, AT_EACCESS) != 0) 2497 if (sys_access ("C:/.emacs", F_OK) != 0)
2092 { 2498 {
2093 HRESULT profile_result; 2499 HRESULT profile_result;
2094 /* Dynamically load ShGetFolderPath, as it won't exist on versions 2500 /* Dynamically load ShGetFolderPath, as it won't exist on versions
@@ -2135,7 +2541,7 @@ init_environment (char ** argv)
2135 char *p; 2541 char *p;
2136 char modname[MAX_PATH]; 2542 char modname[MAX_PATH];
2137 2543
2138 if (!GetModuleFileName (NULL, modname, MAX_PATH)) 2544 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2139 emacs_abort (); 2545 emacs_abort ();
2140 if ((p = _mbsrchr (modname, '\\')) == NULL) 2546 if ((p = _mbsrchr (modname, '\\')) == NULL)
2141 emacs_abort (); 2547 emacs_abort ();
@@ -2164,33 +2570,6 @@ init_environment (char ** argv)
2164 _putenv (strdup (buf)); 2570 _putenv (strdup (buf));
2165 } 2571 }
2166 } 2572 }
2167 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2168
2169 /* FIXME: should use substring of get_emacs_configuration ().
2170 But I don't think the Windows build supports alpha, mips etc
2171 anymore, so have taken the easy option for now. */
2172 else if (p && (xstrcasecmp (p, "\\i386") == 0
2173 || xstrcasecmp (p, "\\AMD64") == 0))
2174 {
2175 *p = 0;
2176 p = _mbsrchr (modname, '\\');
2177 if (p != NULL)
2178 {
2179 *p = 0;
2180 p = _mbsrchr (modname, '\\');
2181 if (p && xstrcasecmp (p, "\\src") == 0)
2182 {
2183 char buf[SET_ENV_BUF_SIZE];
2184
2185 *p = 0;
2186 for (p = modname; *p; p = CharNext (p))
2187 if (*p == '\\') *p = '/';
2188
2189 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2190 _putenv (strdup (buf));
2191 }
2192 }
2193 }
2194 } 2573 }
2195 2574
2196 for (i = 0; i < N_ENV_VARS; i++) 2575 for (i = 0; i < N_ENV_VARS; i++)
@@ -2226,8 +2605,7 @@ init_environment (char ** argv)
2226 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe"); 2605 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2227 ExpandEnvironmentStrings ((LPSTR) fname, bufc, 2606 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2228 sizeof (bufc)); 2607 sizeof (bufc));
2229 if (faccessat (AT_FDCWD, bufc, F_OK, AT_EACCESS) 2608 if (sys_access (bufc, F_OK) == 0)
2230 == 0)
2231 { 2609 {
2232 lpval = bufc; 2610 lpval = bufc;
2233 dwType = REG_SZ; 2611 dwType = REG_SZ;
@@ -2307,13 +2685,27 @@ init_environment (char ** argv)
2307 /* Remember the initial working directory for getcwd. */ 2685 /* Remember the initial working directory for getcwd. */
2308 /* FIXME: Do we need to resolve possible symlinks in startup_dir? 2686 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2309 Does it matter anywhere in Emacs? */ 2687 Does it matter anywhere in Emacs? */
2310 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) 2688 if (w32_unicode_filenames)
2311 emacs_abort (); 2689 {
2690 wchar_t wstartup_dir[MAX_PATH];
2691
2692 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2693 emacs_abort ();
2694 filename_from_utf16 (wstartup_dir, startup_dir);
2695 }
2696 else
2697 {
2698 char astartup_dir[MAX_PATH];
2699
2700 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2701 emacs_abort ();
2702 filename_from_ansi (astartup_dir, startup_dir);
2703 }
2312 2704
2313 { 2705 {
2314 static char modname[MAX_PATH]; 2706 static char modname[MAX_PATH];
2315 2707
2316 if (!GetModuleFileName (NULL, modname, MAX_PATH)) 2708 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2317 emacs_abort (); 2709 emacs_abort ();
2318 argv[0] = modname; 2710 argv[0] = modname;
2319 } 2711 }
@@ -2331,170 +2723,18 @@ init_environment (char ** argv)
2331char * 2723char *
2332emacs_root_dir (void) 2724emacs_root_dir (void)
2333{ 2725{
2334 static char root_dir[FILENAME_MAX]; 2726 static char root_dir[MAX_UTF8_PATH];
2335 const char *p; 2727 const char *p;
2336 2728
2337 p = getenv ("emacs_dir"); 2729 p = getenv ("emacs_dir");
2338 if (p == NULL) 2730 if (p == NULL)
2339 emacs_abort (); 2731 emacs_abort ();
2340 strcpy (root_dir, p); 2732 filename_from_ansi (p, root_dir);
2341 root_dir[parse_root (root_dir, NULL)] = '\0'; 2733 root_dir[parse_root (root_dir, NULL)] = '\0';
2342 dostounix_filename (root_dir, 0); 2734 dostounix_filename (root_dir);
2343 return root_dir; 2735 return root_dir;
2344} 2736}
2345 2737
2346/* We don't have scripts to automatically determine the system configuration
2347 for Emacs before it's compiled, and we don't want to have to make the
2348 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2349 routine. */
2350
2351char *
2352get_emacs_configuration (void)
2353{
2354 char *arch, *oem, *os;
2355 int build_num;
2356 static char configuration_buffer[32];
2357
2358 /* Determine the processor type. */
2359 switch (get_processor_type ())
2360 {
2361
2362#ifdef PROCESSOR_INTEL_386
2363 case PROCESSOR_INTEL_386:
2364 case PROCESSOR_INTEL_486:
2365 case PROCESSOR_INTEL_PENTIUM:
2366#ifdef _WIN64
2367 arch = "amd64";
2368#else
2369 arch = "i386";
2370#endif
2371 break;
2372#endif
2373#ifdef PROCESSOR_AMD_X8664
2374 case PROCESSOR_AMD_X8664:
2375 arch = "amd64";
2376 break;
2377#endif
2378
2379#ifdef PROCESSOR_MIPS_R2000
2380 case PROCESSOR_MIPS_R2000:
2381 case PROCESSOR_MIPS_R3000:
2382 case PROCESSOR_MIPS_R4000:
2383 arch = "mips";
2384 break;
2385#endif
2386
2387#ifdef PROCESSOR_ALPHA_21064
2388 case PROCESSOR_ALPHA_21064:
2389 arch = "alpha";
2390 break;
2391#endif
2392
2393 default:
2394 arch = "unknown";
2395 break;
2396 }
2397
2398 /* Use the OEM field to reflect the compiler/library combination. */
2399#ifdef _MSC_VER
2400#define COMPILER_NAME "msvc"
2401#else
2402#ifdef __GNUC__
2403#define COMPILER_NAME "mingw"
2404#else
2405#define COMPILER_NAME "unknown"
2406#endif
2407#endif
2408 oem = COMPILER_NAME;
2409
2410 switch (osinfo_cache.dwPlatformId) {
2411 case VER_PLATFORM_WIN32_NT:
2412 os = "nt";
2413 build_num = osinfo_cache.dwBuildNumber;
2414 break;
2415 case VER_PLATFORM_WIN32_WINDOWS:
2416 if (osinfo_cache.dwMinorVersion == 0) {
2417 os = "windows95";
2418 } else {
2419 os = "windows98";
2420 }
2421 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2422 break;
2423 case VER_PLATFORM_WIN32s:
2424 /* Not supported, should not happen. */
2425 os = "windows32s";
2426 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2427 break;
2428 default:
2429 os = "unknown";
2430 build_num = 0;
2431 break;
2432 }
2433
2434 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
2435 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
2436 get_w32_major_version (), get_w32_minor_version (), build_num);
2437 } else {
2438 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
2439 }
2440
2441 return configuration_buffer;
2442}
2443
2444char *
2445get_emacs_configuration_options (void)
2446{
2447 static char *options_buffer;
2448 char cv[32]; /* Enough for COMPILER_VERSION. */
2449 char *options[] = {
2450 cv, /* To be filled later. */
2451#ifdef EMACSDEBUG
2452 " --no-opt",
2453#endif
2454#ifdef ENABLE_CHECKING
2455 " --enable-checking",
2456#endif
2457 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2458 with a starting space to save work here. */
2459#ifdef USER_CFLAGS
2460 " --cflags", USER_CFLAGS,
2461#endif
2462#ifdef USER_LDFLAGS
2463 " --ldflags", USER_LDFLAGS,
2464#endif
2465 NULL
2466 };
2467 size_t size = 0;
2468 int i;
2469
2470/* Work out the effective configure options for this build. */
2471#ifdef _MSC_VER
2472#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2473#else
2474#ifdef __GNUC__
2475#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2476#else
2477#define COMPILER_VERSION ""
2478#endif
2479#endif
2480
2481 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
2482 return "Error: not enough space for compiler version";
2483 cv[sizeof (cv) - 1] = '\0';
2484
2485 for (i = 0; options[i]; i++)
2486 size += strlen (options[i]);
2487
2488 options_buffer = xmalloc (size + 1);
2489 options_buffer[0] = '\0';
2490
2491 for (i = 0; options[i]; i++)
2492 strcat (options_buffer, options[i]);
2493
2494 return options_buffer;
2495}
2496
2497
2498#include <sys/timeb.h> 2738#include <sys/timeb.h>
2499 2739
2500/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */ 2740/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
@@ -2649,6 +2889,7 @@ static void
2649add_volume_info (char * root_dir, volume_info_data * info) 2889add_volume_info (char * root_dir, volume_info_data * info)
2650{ 2890{
2651 info->root_dir = xstrdup (root_dir); 2891 info->root_dir = xstrdup (root_dir);
2892 unixtodos_filename (info->root_dir);
2652 info->next = volume_cache; 2893 info->next = volume_cache;
2653 volume_cache = info; 2894 volume_cache = info;
2654} 2895}
@@ -2661,14 +2902,30 @@ static volume_info_data *
2661GetCachedVolumeInformation (char * root_dir) 2902GetCachedVolumeInformation (char * root_dir)
2662{ 2903{
2663 volume_info_data * info; 2904 volume_info_data * info;
2664 char default_root[ MAX_PATH ]; 2905 char default_root[ MAX_UTF8_PATH ];
2906 char name[MAX_PATH+1];
2907 char type[MAX_PATH+1];
2665 2908
2666 /* NULL for root_dir means use root from current directory. */ 2909 /* NULL for root_dir means use root from current directory. */
2667 if (root_dir == NULL) 2910 if (root_dir == NULL)
2668 { 2911 {
2669 if (GetCurrentDirectory (MAX_PATH, default_root) == 0) 2912 if (w32_unicode_filenames)
2670 return NULL; 2913 {
2671 parse_root (default_root, &root_dir); 2914 wchar_t curdirw[MAX_PATH];
2915
2916 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
2917 return NULL;
2918 filename_from_utf16 (curdirw, default_root);
2919 }
2920 else
2921 {
2922 char curdira[MAX_PATH];
2923
2924 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
2925 return NULL;
2926 filename_from_ansi (curdira, default_root);
2927 }
2928 parse_root (default_root, (const char **)&root_dir);
2672 *root_dir = 0; 2929 *root_dir = 0;
2673 root_dir = default_root; 2930 root_dir = default_root;
2674 } 2931 }
@@ -2707,20 +2964,47 @@ GetCachedVolumeInformation (char * root_dir)
2707 2964
2708 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) 2965 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2709 { 2966 {
2710 char name[ 256 ];
2711 DWORD serialnum; 2967 DWORD serialnum;
2712 DWORD maxcomp; 2968 DWORD maxcomp;
2713 DWORD flags; 2969 DWORD flags;
2714 char type[ 256 ];
2715 2970
2716 /* Info is not cached, or is stale. */ 2971 /* Info is not cached, or is stale. */
2717 if (!GetVolumeInformation (root_dir, 2972 if (w32_unicode_filenames)
2718 name, sizeof (name), 2973 {
2719 &serialnum, 2974 wchar_t root_w[MAX_PATH];
2720 &maxcomp, 2975 wchar_t name_w[MAX_PATH+1];
2721 &flags, 2976 wchar_t type_w[MAX_PATH+1];
2722 type, sizeof (type))) 2977
2723 return NULL; 2978 filename_to_utf16 (root_dir, root_w);
2979 if (!GetVolumeInformationW (root_w,
2980 name_w, sizeof (name_w),
2981 &serialnum,
2982 &maxcomp,
2983 &flags,
2984 type_w, sizeof (type_w)))
2985 return NULL;
2986 /* Hmm... not really 100% correct, as these 2 are not file
2987 names... */
2988 filename_from_utf16 (name_w, name);
2989 filename_from_utf16 (type_w, type);
2990 }
2991 else
2992 {
2993 char root_a[MAX_PATH];
2994 char name_a[MAX_PATH+1];
2995 char type_a[MAX_PATH+1];
2996
2997 filename_to_ansi (root_dir, root_a);
2998 if (!GetVolumeInformationA (root_a,
2999 name_a, sizeof (name_a),
3000 &serialnum,
3001 &maxcomp,
3002 &flags,
3003 type_a, sizeof (type_a)))
3004 return NULL;
3005 filename_from_ansi (name_a, name);
3006 filename_from_ansi (type_a, type);
3007 }
2724 3008
2725 /* Cache the volume information for future use, overwriting existing 3009 /* Cache the volume information for future use, overwriting existing
2726 entry if present. */ 3010 entry if present. */
@@ -2736,6 +3020,7 @@ GetCachedVolumeInformation (char * root_dir)
2736 } 3020 }
2737 3021
2738 info->name = xstrdup (name); 3022 info->name = xstrdup (name);
3023 unixtodos_filename (info->name);
2739 info->serialnum = serialnum; 3024 info->serialnum = serialnum;
2740 info->maxcomp = maxcomp; 3025 info->maxcomp = maxcomp;
2741 info->flags = flags; 3026 info->flags = flags;
@@ -2758,53 +3043,23 @@ GetCachedVolumeInformation (char * root_dir)
2758static int 3043static int
2759get_volume_info (const char * name, const char ** pPath) 3044get_volume_info (const char * name, const char ** pPath)
2760{ 3045{
2761 char temp[MAX_PATH]; 3046 char temp[MAX_UTF8_PATH];
2762 char *rootname = NULL; /* default to current volume */ 3047 char *rootname = NULL; /* default to current volume */
2763 volume_info_data * info; 3048 volume_info_data * info;
3049 int root_len = parse_root (name, pPath);
2764 3050
2765 if (name == NULL) 3051 if (name == NULL)
2766 return FALSE; 3052 return FALSE;
2767 3053
2768 /* Find the root name of the volume if given. */ 3054 /* Copy the root name of the volume, if given. */
2769 if (isalpha (name[0]) && name[1] == ':') 3055 if (root_len)
2770 { 3056 {
3057 strncpy (temp, name, root_len);
3058 temp[root_len] = '\0';
3059 unixtodos_filename (temp);
2771 rootname = temp; 3060 rootname = temp;
2772 temp[0] = *name++;
2773 temp[1] = *name++;
2774 temp[2] = '\\';
2775 temp[3] = 0;
2776 }
2777 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2778 {
2779 char *str = temp;
2780 int slashes = 4;
2781 int dbcs_p = max_filename_mbslen () > 1;
2782
2783 rootname = temp;
2784 do
2785 {
2786 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2787 break;
2788 if (!dbcs_p)
2789 *str++ = *name++;
2790 else
2791 {
2792 const char *p = name;
2793
2794 name = CharNextExA (file_name_codepage, name, 0);
2795 memcpy (str, p, name - p);
2796 str += name - p;
2797 }
2798 }
2799 while ( *name );
2800
2801 *str++ = '\\';
2802 *str = 0;
2803 } 3061 }
2804 3062
2805 if (pPath)
2806 *pPath = name;
2807
2808 info = GetCachedVolumeInformation (rootname); 3063 info = GetCachedVolumeInformation (rootname);
2809 if (info != NULL) 3064 if (info != NULL)
2810 { 3065 {
@@ -2826,18 +3081,19 @@ is_fat_volume (const char * name, const char ** pPath)
2826 return FALSE; 3081 return FALSE;
2827} 3082}
2828 3083
2829/* Map filename to a valid 8.3 name if necessary. 3084/* Convert all slashes in a filename to backslashes, and map filename
2830 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */ 3085 to a valid 8.3 name if necessary. The result is a pointer to a
3086 static buffer, so CAVEAT EMPTOR! */
2831const char * 3087const char *
2832map_w32_filename (const char * name, const char ** pPath) 3088map_w32_filename (const char * name, const char ** pPath)
2833{ 3089{
2834 static char shortname[MAX_PATH]; 3090 static char shortname[MAX_UTF8_PATH];
2835 char * str = shortname; 3091 char * str = shortname;
2836 char c; 3092 char c;
2837 char * path; 3093 char * path;
2838 const char * save_name = name; 3094 const char * save_name = name;
2839 3095
2840 if (strlen (name) >= MAX_PATH) 3096 if (strlen (name) >= sizeof (shortname))
2841 { 3097 {
2842 /* Return a filename which will cause callers to fail. */ 3098 /* Return a filename which will cause callers to fail. */
2843 strcpy (shortname, "?"); 3099 strcpy (shortname, "?");
@@ -2904,7 +3160,7 @@ map_w32_filename (const char * name, const char ** pPath)
2904 str[-1] = c; /* replace last character of part */ 3160 str[-1] = c; /* replace last character of part */
2905 /* FALLTHRU */ 3161 /* FALLTHRU */
2906 default: 3162 default:
2907 if ( left ) 3163 if ( left && 'A' <= c && c <= 'Z' )
2908 { 3164 {
2909 *str++ = tolower (c); /* map to lower case (looks nicer) */ 3165 *str++ = tolower (c); /* map to lower case (looks nicer) */
2910 left--; 3166 left--;
@@ -2939,25 +3195,31 @@ is_exec (const char * name)
2939 xstrcasecmp (p, ".cmd") == 0)); 3195 xstrcasecmp (p, ".cmd") == 0));
2940} 3196}
2941 3197
2942/* Emulate the Unix directory procedures opendir, closedir, 3198/* Emulate the Unix directory procedures opendir, closedir, and
2943 and readdir. We can't use the procedures supplied in sysdep.c, 3199 readdir. We rename them to sys_* names because some versions of
2944 so we provide them here. */ 3200 MinGW startup code call opendir and readdir to glob wildcards, and
3201 the code that calls them doesn't grok UTF-8 encoded file names we
3202 produce in dirent->d_name[]. */
2945 3203
2946struct dirent dir_static; /* simulated directory contents */ 3204struct dirent dir_static; /* simulated directory contents */
2947static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; 3205static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2948static int dir_is_fat; 3206static int dir_is_fat;
2949static char dir_pathname[MAXPATHLEN+1]; 3207static char dir_pathname[MAX_UTF8_PATH];
2950static WIN32_FIND_DATA dir_find_data; 3208static WIN32_FIND_DATAW dir_find_data_w;
3209static WIN32_FIND_DATAA dir_find_data_a;
3210#define DIR_FIND_DATA_W 1
3211#define DIR_FIND_DATA_A 2
3212static int last_dir_find_data = -1;
2951 3213
2952/* Support shares on a network resource as subdirectories of a read-only 3214/* Support shares on a network resource as subdirectories of a read-only
2953 root directory. */ 3215 root directory. */
2954static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; 3216static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2955static HANDLE open_unc_volume (const char *); 3217static HANDLE open_unc_volume (const char *);
2956static char *read_unc_volume (HANDLE, char *, int); 3218static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
2957static void close_unc_volume (HANDLE); 3219static void close_unc_volume (HANDLE);
2958 3220
2959DIR * 3221DIR *
2960opendir (const char *filename) 3222sys_opendir (const char *filename)
2961{ 3223{
2962 DIR *dirp; 3224 DIR *dirp;
2963 3225
@@ -2986,8 +3248,8 @@ opendir (const char *filename)
2986 dirp->dd_loc = 0; 3248 dirp->dd_loc = 0;
2987 dirp->dd_size = 0; 3249 dirp->dd_size = 0;
2988 3250
2989 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN); 3251 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
2990 dir_pathname[MAXPATHLEN] = '\0'; 3252 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
2991 /* Note: We don't support symlinks to file names on FAT volumes. 3253 /* Note: We don't support symlinks to file names on FAT volumes.
2992 Doing so would mean punishing 99.99% of use cases by resolving 3254 Doing so would mean punishing 99.99% of use cases by resolving
2993 all the possible symlinks in FILENAME, recursively. */ 3255 all the possible symlinks in FILENAME, recursively. */
@@ -2997,7 +3259,7 @@ opendir (const char *filename)
2997} 3259}
2998 3260
2999void 3261void
3000closedir (DIR *dirp) 3262sys_closedir (DIR *dirp)
3001{ 3263{
3002 /* If we have a find-handle open, close it. */ 3264 /* If we have a find-handle open, close it. */
3003 if (dir_find_handle != INVALID_HANDLE_VALUE) 3265 if (dir_find_handle != INVALID_HANDLE_VALUE)
@@ -3014,52 +3276,65 @@ closedir (DIR *dirp)
3014} 3276}
3015 3277
3016struct dirent * 3278struct dirent *
3017readdir (DIR *dirp) 3279sys_readdir (DIR *dirp)
3018{ 3280{
3019 int downcase = !NILP (Vw32_downcase_file_names); 3281 int downcase = !NILP (Vw32_downcase_file_names);
3020 3282
3021 if (wnet_enum_handle != INVALID_HANDLE_VALUE) 3283 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3022 { 3284 {
3023 if (!read_unc_volume (wnet_enum_handle, 3285 if (!read_unc_volume (wnet_enum_handle,
3024 dir_find_data.cFileName, 3286 dir_find_data_w.cFileName,
3287 dir_find_data_a.cFileName,
3025 MAX_PATH)) 3288 MAX_PATH))
3026 return NULL; 3289 return NULL;
3027 } 3290 }
3028 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ 3291 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3029 else if (dir_find_handle == INVALID_HANDLE_VALUE) 3292 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3030 { 3293 {
3031 char filename[MAXNAMLEN + 3]; 3294 char filename[MAX_UTF8_PATH + 2];
3032 int ln; 3295 int ln;
3033 int dbcs_p = max_filename_mbslen () > 1;
3034 3296
3035 strcpy (filename, dir_pathname); 3297 strcpy (filename, dir_pathname);
3036 ln = strlen (filename) - 1; 3298 ln = strlen (filename) - 1;
3037 if (!dbcs_p) 3299 if (!IS_DIRECTORY_SEP (filename[ln]))
3038 { 3300 strcat (filename, "\\");
3039 if (!IS_DIRECTORY_SEP (filename[ln]))
3040 strcat (filename, "\\");
3041 }
3042 else
3043 {
3044 char *end = filename + ln + 1;
3045 char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
3046
3047 if (!IS_DIRECTORY_SEP (*last_char))
3048 strcat (filename, "\\");
3049 }
3050 strcat (filename, "*"); 3301 strcat (filename, "*");
3051 3302
3052 /* Note: No need to resolve symlinks in FILENAME, because 3303 /* Note: No need to resolve symlinks in FILENAME, because
3053 FindFirst opens the directory that is the target of a 3304 FindFirst opens the directory that is the target of a
3054 symlink. */ 3305 symlink. */
3055 dir_find_handle = FindFirstFile (filename, &dir_find_data); 3306 if (w32_unicode_filenames)
3307 {
3308 wchar_t fnw[MAX_PATH];
3309
3310 filename_to_utf16 (filename, fnw);
3311 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3312 }
3313 else
3314 {
3315 char fna[MAX_PATH];
3316
3317 filename_to_ansi (filename, fna);
3318 /* If FILENAME is not representable by the current ANSI
3319 codepage, we don't want FindFirstFileA to interpret the
3320 '?' characters as a wildcard. */
3321 if (_mbspbrk (fna, "?"))
3322 dir_find_handle = INVALID_HANDLE_VALUE;
3323 else
3324 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3325 }
3056 3326
3057 if (dir_find_handle == INVALID_HANDLE_VALUE) 3327 if (dir_find_handle == INVALID_HANDLE_VALUE)
3058 return NULL; 3328 return NULL;
3059 } 3329 }
3330 else if (w32_unicode_filenames)
3331 {
3332 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3333 return NULL;
3334 }
3060 else 3335 else
3061 { 3336 {
3062 if (!FindNextFile (dir_find_handle, &dir_find_data)) 3337 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3063 return NULL; 3338 return NULL;
3064 } 3339 }
3065 3340
@@ -3067,112 +3342,155 @@ readdir (DIR *dirp)
3067 value returned by stat(). */ 3342 value returned by stat(). */
3068 dir_static.d_ino = 1; 3343 dir_static.d_ino = 1;
3069 3344
3070 strcpy (dir_static.d_name, dir_find_data.cFileName); 3345 if (w32_unicode_filenames)
3071
3072 /* If the file name in cFileName[] includes `?' characters, it means
3073 the original file name used characters that cannot be represented
3074 by the current ANSI codepage. To avoid total lossage, retrieve
3075 the short 8+3 alias of the long file name. */
3076 if (_mbspbrk (dir_static.d_name, "?"))
3077 { 3346 {
3078 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName); 3347 if (downcase || dir_is_fat)
3079 downcase = 1; /* 8+3 aliases are returned in all caps */ 3348 {
3080 } 3349 wchar_t tem[MAX_PATH];
3081 dir_static.d_namlen = strlen (dir_static.d_name);
3082 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
3083 dir_static.d_namlen - dir_static.d_namlen % 4;
3084 3350
3085 /* If the file name in cFileName[] includes `?' characters, it means 3351 wcscpy (tem, dir_find_data_w.cFileName);
3086 the original file name used characters that cannot be represented 3352 CharLowerW (tem);
3087 by the current ANSI codepage. To avoid total lossage, retrieve 3353 filename_from_utf16 (tem, dir_static.d_name);
3088 the short 8+3 alias of the long file name. */ 3354 }
3089 if (_mbspbrk (dir_find_data.cFileName, "?")) 3355 else
3090 { 3356 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3091 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName); 3357 last_dir_find_data = DIR_FIND_DATA_W;
3092 /* 8+3 aliases are returned in all caps, which could break
3093 various alists that look at filenames' extensions. */
3094 downcase = 1;
3095 } 3358 }
3096 else 3359 else
3097 strcpy (dir_static.d_name, dir_find_data.cFileName);
3098 dir_static.d_namlen = strlen (dir_static.d_name);
3099 if (dir_is_fat)
3100 _mbslwr (dir_static.d_name);
3101 else if (downcase)
3102 { 3360 {
3103 register char *p; 3361 char tem[MAX_PATH];
3104 int dbcs_p = max_filename_mbslen () > 1; 3362
3105 for (p = dir_static.d_name; *p; ) 3363 /* If the file name in cFileName[] includes `?' characters, it
3364 means the original file name used characters that cannot be
3365 represented by the current ANSI codepage. To avoid total
3366 lossage, retrieve the short 8+3 alias of the long file
3367 name. */
3368 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3106 { 3369 {
3107 if (*p >= 'a' && *p <= 'z') 3370 strcpy (tem, dir_find_data_a.cAlternateFileName);
3108 break; 3371 /* 8+3 aliases are returned in all caps, which could break
3109 if (dbcs_p) 3372 various alists that look at filenames' extensions. */
3110 p = CharNextExA (file_name_codepage, p, 0); 3373 downcase = 1;
3111 else
3112 p++;
3113 } 3374 }
3114 if (!*p) 3375 else if (downcase || dir_is_fat)
3115 _mbslwr (dir_static.d_name); 3376 strcpy (tem, dir_find_data_a.cFileName);
3377 else
3378 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3379 if (downcase || dir_is_fat)
3380 {
3381 _mbslwr (tem);
3382 filename_from_ansi (tem, dir_static.d_name);
3383 }
3384 last_dir_find_data = DIR_FIND_DATA_A;
3116 } 3385 }
3117 3386
3387 dir_static.d_namlen = strlen (dir_static.d_name);
3388 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3389 dir_static.d_namlen - dir_static.d_namlen % 4;
3390
3118 return &dir_static; 3391 return &dir_static;
3119} 3392}
3120 3393
3121static HANDLE 3394static HANDLE
3122open_unc_volume (const char *path) 3395open_unc_volume (const char *path)
3123{ 3396{
3124 NETRESOURCE nr; 3397 const char *fn = map_w32_filename (path, NULL);
3398 DWORD result;
3125 HANDLE henum; 3399 HANDLE henum;
3126 int result;
3127 3400
3128 nr.dwScope = RESOURCE_GLOBALNET; 3401 if (w32_unicode_filenames)
3129 nr.dwType = RESOURCETYPE_DISK; 3402 {
3130 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; 3403 NETRESOURCEW nrw;
3131 nr.dwUsage = RESOURCEUSAGE_CONTAINER; 3404 wchar_t fnw[MAX_PATH];
3132 nr.lpLocalName = NULL; 3405
3133 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL); 3406 nrw.dwScope = RESOURCE_GLOBALNET;
3134 nr.lpComment = NULL; 3407 nrw.dwType = RESOURCETYPE_DISK;
3135 nr.lpProvider = NULL; 3408 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3409 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3410 nrw.lpLocalName = NULL;
3411 filename_to_utf16 (fn, fnw);
3412 nrw.lpRemoteName = fnw;
3413 nrw.lpComment = NULL;
3414 nrw.lpProvider = NULL;
3136 3415
3137 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 3416 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3138 RESOURCEUSAGE_CONNECTABLE, &nr, &henum); 3417 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3418 }
3419 else
3420 {
3421 NETRESOURCEA nra;
3422 char fna[MAX_PATH];
3139 3423
3424 nra.dwScope = RESOURCE_GLOBALNET;
3425 nra.dwType = RESOURCETYPE_DISK;
3426 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3427 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3428 nra.lpLocalName = NULL;
3429 filename_to_ansi (fn, fna);
3430 nra.lpRemoteName = fna;
3431 nra.lpComment = NULL;
3432 nra.lpProvider = NULL;
3433
3434 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3435 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3436 }
3140 if (result == NO_ERROR) 3437 if (result == NO_ERROR)
3141 return henum; 3438 return henum;
3142 else 3439 else
3143 return INVALID_HANDLE_VALUE; 3440 return INVALID_HANDLE_VALUE;
3144} 3441}
3145 3442
3146static char * 3443static void *
3147read_unc_volume (HANDLE henum, char *readbuf, int size) 3444read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3148{ 3445{
3149 DWORD count; 3446 DWORD count;
3150 int result; 3447 int result;
3151 DWORD bufsize = 512;
3152 char *buffer; 3448 char *buffer;
3153 char *ptr; 3449 DWORD bufsize = 512;
3154 int dbcs_p = max_filename_mbslen () > 1; 3450 void *retval;
3155 3451
3156 count = 1; 3452 count = 1;
3157 buffer = alloca (bufsize); 3453 if (w32_unicode_filenames)
3158 result = WNetEnumResource (henum, &count, buffer, &bufsize); 3454 {
3159 if (result != NO_ERROR) 3455 wchar_t *ptrw;
3160 return NULL;
3161 3456
3162 /* WNetEnumResource returns \\resource\share...skip forward to "share". */ 3457 bufsize *= 2;
3163 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; 3458 buffer = alloca (bufsize);
3164 ptr += 2; 3459 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3165 if (!dbcs_p) 3460 if (result != NO_ERROR)
3166 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; 3461 return NULL;
3462 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3463 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3464 ptrw += 2;
3465 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3466 ptrw++;
3467 wcsncpy (fname_w, ptrw, size);
3468 retval = fname_w;
3469 }
3167 else 3470 else
3168 { 3471 {
3169 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) 3472 int dbcs_p = max_filename_mbslen () > 1;
3170 ptr = CharNextExA (file_name_codepage, ptr, 0); 3473 char *ptra;
3474
3475 buffer = alloca (bufsize);
3476 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3477 if (result != NO_ERROR)
3478 return NULL;
3479 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3480 ptra += 2;
3481 if (!dbcs_p)
3482 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3483 else
3484 {
3485 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3486 ptra = CharNextExA (file_name_codepage, ptra, 0);
3487 }
3488 ptra++;
3489 strncpy (fname_a, ptra, size);
3490 retval = fname_a;
3171 } 3491 }
3172 ptr++;
3173 3492
3174 strncpy (readbuf, ptr, size); 3493 return retval;
3175 return readbuf;
3176} 3494}
3177 3495
3178static void 3496static void
@@ -3203,13 +3521,12 @@ unc_volume_file_attributes (const char *path)
3203static void 3521static void
3204logon_network_drive (const char *path) 3522logon_network_drive (const char *path)
3205{ 3523{
3206 NETRESOURCE resource; 3524 char share[MAX_UTF8_PATH];
3207 char share[MAX_PATH];
3208 int n_slashes; 3525 int n_slashes;
3209 char drive[4]; 3526 char drive[4];
3210 UINT drvtype; 3527 UINT drvtype;
3211 char *p; 3528 char *p;
3212 int dbcs_p; 3529 DWORD val;
3213 3530
3214 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) 3531 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3215 drvtype = DRIVE_REMOTE; 3532 drvtype = DRIVE_REMOTE;
@@ -3229,28 +3546,70 @@ logon_network_drive (const char *path)
3229 return; 3546 return;
3230 3547
3231 n_slashes = 2; 3548 n_slashes = 2;
3232 strncpy (share, path, MAX_PATH); 3549 strncpy (share, path, MAX_UTF8_PATH);
3233 /* Truncate to just server and share name. */ 3550 /* Truncate to just server and share name. */
3234 dbcs_p = max_filename_mbslen () > 1; 3551 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3235 for (p = share + 2; *p && p < share + MAX_PATH; )
3236 { 3552 {
3237 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3) 3553 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3238 { 3554 {
3239 *p = '\0'; 3555 *p = '\0';
3240 break; 3556 break;
3241 } 3557 }
3242 if (dbcs_p)
3243 p = CharNextExA (file_name_codepage, p, 0);
3244 else
3245 p++;
3246 } 3558 }
3247 3559
3248 resource.dwType = RESOURCETYPE_DISK; 3560 if (w32_unicode_filenames)
3249 resource.lpLocalName = NULL; 3561 {
3250 resource.lpRemoteName = share; 3562 NETRESOURCEW resourcew;
3251 resource.lpProvider = NULL; 3563 wchar_t share_w[MAX_PATH];
3564
3565 resourcew.dwScope = RESOURCE_GLOBALNET;
3566 resourcew.dwType = RESOURCETYPE_DISK;
3567 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3568 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3569 resourcew.lpLocalName = NULL;
3570 filename_to_utf16 (share, share_w);
3571 resourcew.lpRemoteName = share_w;
3572 resourcew.lpProvider = NULL;
3573
3574 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3575 }
3576 else
3577 {
3578 NETRESOURCEA resourcea;
3579 char share_a[MAX_PATH];
3580
3581 resourcea.dwScope = RESOURCE_GLOBALNET;
3582 resourcea.dwType = RESOURCETYPE_DISK;
3583 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3584 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3585 resourcea.lpLocalName = NULL;
3586 filename_to_ansi (share, share_a);
3587 resourcea.lpRemoteName = share_a;
3588 resourcea.lpProvider = NULL;
3252 3589
3253 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE); 3590 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3591 }
3592
3593 switch (val)
3594 {
3595 case NO_ERROR:
3596 case ERROR_ALREADY_ASSIGNED:
3597 break;
3598 case ERROR_ACCESS_DENIED:
3599 case ERROR_LOGON_FAILURE:
3600 errno = EACCES;
3601 break;
3602 case ERROR_BUSY:
3603 errno = EAGAIN;
3604 break;
3605 case ERROR_BAD_NET_NAME:
3606 case ERROR_NO_NET_OR_BAD_PATH:
3607 case ERROR_NO_NETWORK:
3608 case ERROR_CANCELLED:
3609 default:
3610 errno = ENOENT;
3611 break;
3612 }
3254} 3613}
3255 3614
3256/* Emulate faccessat(2). */ 3615/* Emulate faccessat(2). */
@@ -3278,7 +3637,22 @@ faccessat (int dirfd, const char * path, int mode, int flags)
3278 && (flags & AT_SYMLINK_NOFOLLOW) == 0) 3637 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3279 path = chase_symlinks (path); 3638 path = chase_symlinks (path);
3280 3639
3281 if ((attributes = GetFileAttributes (path)) == -1) 3640 if (w32_unicode_filenames)
3641 {
3642 wchar_t path_w[MAX_PATH];
3643
3644 filename_to_utf16 (path, path_w);
3645 attributes = GetFileAttributesW (path_w);
3646 }
3647 else
3648 {
3649 char path_a[MAX_PATH];
3650
3651 filename_to_ansi (path, path_a);
3652 attributes = GetFileAttributesA (path_a);
3653 }
3654
3655 if (attributes == -1)
3282 { 3656 {
3283 DWORD w32err = GetLastError (); 3657 DWORD w32err = GetLastError ();
3284 3658
@@ -3326,6 +3700,62 @@ faccessat (int dirfd, const char * path, int mode, int flags)
3326 return 0; 3700 return 0;
3327} 3701}
3328 3702
3703/* A version of 'access' to be used locally with file names in
3704 locale-specific encoding. Does not resolve symlinks and does not
3705 support file names on FAT12 and FAT16 volumes, but that's OK, since
3706 we only invoke this function for files inside the Emacs source or
3707 installation tree, on directories (so any symlinks should have the
3708 directory bit set), and on short file names such as "C:/.emacs". */
3709static int
3710sys_access (const char *fname, int mode)
3711{
3712 char fname_copy[MAX_PATH], *p;
3713 DWORD attributes;
3714
3715 strcpy (fname_copy, fname);
3716 /* Do the equivalent of unixtodos_filename. */
3717 for (p = fname_copy; *p; p = CharNext (p))
3718 if (*p == '/')
3719 *p = '\\';
3720
3721 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3722 {
3723 DWORD w32err = GetLastError ();
3724
3725 switch (w32err)
3726 {
3727 case ERROR_INVALID_NAME:
3728 case ERROR_BAD_PATHNAME:
3729 case ERROR_FILE_NOT_FOUND:
3730 case ERROR_BAD_NETPATH:
3731 errno = ENOENT;
3732 break;
3733 default:
3734 errno = EACCES;
3735 break;
3736 }
3737 return -1;
3738 }
3739 if ((mode & X_OK) != 0
3740 && !(is_exec (fname_copy)
3741 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3742 {
3743 errno = EACCES;
3744 return -1;
3745 }
3746 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3747 {
3748 errno = EACCES;
3749 return -1;
3750 }
3751 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3752 {
3753 errno = EACCES;
3754 return -1;
3755 }
3756 return 0;
3757}
3758
3329/* Shadow some MSVC runtime functions to map requests for long filenames 3759/* Shadow some MSVC runtime functions to map requests for long filenames
3330 to reasonable short names if necessary. This was originally added to 3760 to reasonable short names if necessary. This was originally added to
3331 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support 3761 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
@@ -3334,20 +3764,63 @@ faccessat (int dirfd, const char * path, int mode, int flags)
3334int 3764int
3335sys_chdir (const char * path) 3765sys_chdir (const char * path)
3336{ 3766{
3337 return _chdir (map_w32_filename (path, NULL)); 3767 path = map_w32_filename (path, NULL);
3768 if (w32_unicode_filenames)
3769 {
3770 wchar_t newdir_w[MAX_PATH];
3771
3772 if (filename_to_utf16 (path, newdir_w) == 0)
3773 return _wchdir (newdir_w);
3774 return -1;
3775 }
3776 else
3777 {
3778 char newdir_a[MAX_PATH];
3779
3780 if (filename_to_ansi (path, newdir_a) == 0)
3781 return _chdir (newdir_a);
3782 return -1;
3783 }
3338} 3784}
3339 3785
3340int 3786int
3341sys_chmod (const char * path, int mode) 3787sys_chmod (const char * path, int mode)
3342{ 3788{
3343 path = chase_symlinks (map_w32_filename (path, NULL)); 3789 path = chase_symlinks (map_w32_filename (path, NULL));
3344 return _chmod (path, mode); 3790 if (w32_unicode_filenames)
3791 {
3792 wchar_t path_w[MAX_PATH];
3793
3794 filename_to_utf16 (path, path_w);
3795 return _wchmod (path_w, mode);
3796 }
3797 else
3798 {
3799 char path_a[MAX_PATH];
3800
3801 filename_to_ansi (path, path_a);
3802 return _chmod (path_a, mode);
3803 }
3345} 3804}
3346 3805
3347int 3806int
3348sys_creat (const char * path, int mode) 3807sys_creat (const char * path, int mode)
3349{ 3808{
3350 return _creat (map_w32_filename (path, NULL), mode); 3809 path = map_w32_filename (path, NULL);
3810 if (w32_unicode_filenames)
3811 {
3812 wchar_t path_w[MAX_PATH];
3813
3814 filename_to_utf16 (path, path_w);
3815 return _wcreat (path_w, mode);
3816 }
3817 else
3818 {
3819 char path_a[MAX_PATH];
3820
3821 filename_to_ansi (path, path_a);
3822 return _creat (path_a, mode);
3823 }
3351} 3824}
3352 3825
3353FILE * 3826FILE *
@@ -3387,7 +3860,21 @@ sys_fopen (const char * path, const char * mode)
3387 } 3860 }
3388 else break; 3861 else break;
3389 3862
3390 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644); 3863 path = map_w32_filename (path, NULL);
3864 if (w32_unicode_filenames)
3865 {
3866 wchar_t path_w[MAX_PATH];
3867
3868 filename_to_utf16 (path, path_w);
3869 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3870 }
3871 else
3872 {
3873 char path_a[MAX_PATH];
3874
3875 filename_to_ansi (path, path_a);
3876 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
3877 }
3391 if (fd < 0) 3878 if (fd < 0)
3392 return NULL; 3879 return NULL;
3393 3880
@@ -3400,7 +3887,9 @@ sys_link (const char * old, const char * new)
3400{ 3887{
3401 HANDLE fileh; 3888 HANDLE fileh;
3402 int result = -1; 3889 int result = -1;
3403 char oldname[MAX_PATH], newname[MAX_PATH]; 3890 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3891 wchar_t oldname_w[MAX_PATH];
3892 char oldname_a[MAX_PATH];
3404 3893
3405 if (old == NULL || new == NULL) 3894 if (old == NULL || new == NULL)
3406 { 3895 {
@@ -3411,8 +3900,18 @@ sys_link (const char * old, const char * new)
3411 strcpy (oldname, map_w32_filename (old, NULL)); 3900 strcpy (oldname, map_w32_filename (old, NULL));
3412 strcpy (newname, map_w32_filename (new, NULL)); 3901 strcpy (newname, map_w32_filename (new, NULL));
3413 3902
3414 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING, 3903 if (w32_unicode_filenames)
3415 FILE_FLAG_BACKUP_SEMANTICS, NULL); 3904 {
3905 filename_to_utf16 (oldname, oldname_w);
3906 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
3907 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3908 }
3909 else
3910 {
3911 filename_to_ansi (oldname, oldname_a);
3912 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
3913 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3914 }
3416 if (fileh != INVALID_HANDLE_VALUE) 3915 if (fileh != INVALID_HANDLE_VALUE)
3417 { 3916 {
3418 int wlen; 3917 int wlen;
@@ -3429,7 +3928,10 @@ sys_link (const char * old, const char * new)
3429 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */ 3928 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3430 } data; 3929 } data;
3431 3930
3432 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1, 3931 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3932 indicates that flag is unsupported for CP_UTF8, and OTOH says
3933 it is the default anyway. */
3934 wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
3433 data.wid.cStreamName, MAX_PATH); 3935 data.wid.cStreamName, MAX_PATH);
3434 if (wlen > 0) 3936 if (wlen > 0)
3435 { 3937 {
@@ -3453,9 +3955,40 @@ sys_link (const char * old, const char * new)
3453 } 3955 }
3454 else 3956 else
3455 { 3957 {
3456 /* Should try mapping GetLastError to errno; for now just 3958 DWORD err = GetLastError ();
3457 indicate a general error (eg. links not supported). */ 3959 DWORD attributes;
3458 errno = EINVAL; // perhaps EMLINK? 3960
3961 switch (err)
3962 {
3963 case ERROR_ACCESS_DENIED:
3964 /* This is what happens when OLDNAME is a directory,
3965 since Windows doesn't support hard links to
3966 directories. Posix says to set errno to EPERM in
3967 that case. */
3968 if (w32_unicode_filenames)
3969 attributes = GetFileAttributesW (oldname_w);
3970 else
3971 attributes = GetFileAttributesA (oldname_a);
3972 if (attributes != -1
3973 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
3974 errno = EPERM;
3975 else if (attributes == -1
3976 && is_unc_volume (oldname)
3977 && unc_volume_file_attributes (oldname) != -1)
3978 errno = EPERM;
3979 else
3980 errno = EACCES;
3981 break;
3982 case ERROR_TOO_MANY_LINKS:
3983 errno = EMLINK;
3984 break;
3985 case ERROR_NOT_SAME_DEVICE:
3986 errno = EXDEV;
3987 break;
3988 default:
3989 errno = EINVAL;
3990 break;
3991 }
3459 } 3992 }
3460 } 3993 }
3461 3994
@@ -3470,7 +4003,22 @@ sys_link (const char * old, const char * new)
3470int 4003int
3471sys_mkdir (const char * path) 4004sys_mkdir (const char * path)
3472{ 4005{
3473 return _mkdir (map_w32_filename (path, NULL)); 4006 path = map_w32_filename (path, NULL);
4007
4008 if (w32_unicode_filenames)
4009 {
4010 wchar_t path_w[MAX_PATH];
4011
4012 filename_to_utf16 (path, path_w);
4013 return _wmkdir (path_w);
4014 }
4015 else
4016 {
4017 char path_a[MAX_PATH];
4018
4019 filename_to_ansi (path, path_a);
4020 return _mkdir (path_a);
4021 }
3474} 4022}
3475 4023
3476int 4024int
@@ -3479,13 +4027,29 @@ sys_open (const char * path, int oflag, int mode)
3479 const char* mpath = map_w32_filename (path, NULL); 4027 const char* mpath = map_w32_filename (path, NULL);
3480 int res = -1; 4028 int res = -1;
3481 4029
3482 /* If possible, try to open file without _O_CREAT, to be able to 4030 if (w32_unicode_filenames)
3483 write to existing hidden and system files. Force all file 4031 {
3484 handles to be non-inheritable. */ 4032 wchar_t mpath_w[MAX_PATH];
3485 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL)) 4033
3486 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); 4034 filename_to_utf16 (mpath, mpath_w);
3487 if (res < 0) 4035 /* If possible, try to open file without _O_CREAT, to be able to
3488 res = _open (mpath, oflag | _O_NOINHERIT, mode); 4036 write to existing hidden and system files. Force all file
4037 handles to be non-inheritable. */
4038 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4039 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4040 if (res < 0)
4041 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4042 }
4043 else
4044 {
4045 char mpath_a[MAX_PATH];
4046
4047 filename_to_ansi (mpath, mpath_a);
4048 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4049 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4050 if (res < 0)
4051 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4052 }
3489 4053
3490 return res; 4054 return res;
3491} 4055}
@@ -3555,9 +4119,10 @@ int
3555sys_rename_replace (const char *oldname, const char *newname, BOOL force) 4119sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3556{ 4120{
3557 BOOL result; 4121 BOOL result;
3558 char temp[MAX_PATH]; 4122 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
3559 int newname_dev; 4123 int newname_dev;
3560 int oldname_dev; 4124 int oldname_dev;
4125 bool have_temp_a = false;
3561 4126
3562 /* MoveFile on Windows 95 doesn't correctly change the short file name 4127 /* MoveFile on Windows 95 doesn't correctly change the short file name
3563 alias in a number of circumstances (it is not easy to predict when 4128 alias in a number of circumstances (it is not easy to predict when
@@ -3582,17 +4147,20 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3582 char * o; 4147 char * o;
3583 char * p; 4148 char * p;
3584 int i = 0; 4149 int i = 0;
4150 char oldname_a[MAX_PATH];
3585 4151
3586 oldname = map_w32_filename (oldname, NULL); 4152 oldname = map_w32_filename (oldname, NULL);
3587 if ((o = strrchr (oldname, '\\'))) 4153 filename_to_ansi (oldname, oldname_a);
4154 filename_to_ansi (temp, temp_a);
4155 if ((o = strrchr (oldname_a, '\\')))
3588 o++; 4156 o++;
3589 else 4157 else
3590 o = (char *) oldname; 4158 o = (char *) oldname_a;
3591 4159
3592 if ((p = strrchr (temp, '\\'))) 4160 if ((p = strrchr (temp_a, '\\')))
3593 p++; 4161 p++;
3594 else 4162 else
3595 p = temp; 4163 p = temp_a;
3596 4164
3597 do 4165 do
3598 { 4166 {
@@ -3600,12 +4168,13 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3600 seems to make the second rename work properly. */ 4168 seems to make the second rename work properly. */
3601 sprintf (p, "_.%s.%u", o, i); 4169 sprintf (p, "_.%s.%u", o, i);
3602 i++; 4170 i++;
3603 result = rename (oldname, temp); 4171 result = rename (oldname_a, temp_a);
3604 } 4172 }
3605 /* This loop must surely terminate! */ 4173 /* This loop must surely terminate! */
3606 while (result < 0 && errno == EEXIST); 4174 while (result < 0 && errno == EEXIST);
3607 if (result < 0) 4175 if (result < 0)
3608 return -1; 4176 return -1;
4177 have_temp_a = true;
3609 } 4178 }
3610 4179
3611 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists 4180 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
@@ -3624,41 +4193,81 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3624 /* volume_info is set indirectly by map_w32_filename. */ 4193 /* volume_info is set indirectly by map_w32_filename. */
3625 newname_dev = volume_info.serialnum; 4194 newname_dev = volume_info.serialnum;
3626 4195
3627 result = rename (temp, newname); 4196 if (w32_unicode_filenames)
3628
3629 if (result < 0 && force)
3630 { 4197 {
3631 DWORD w32err = GetLastError (); 4198 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
3632 4199
3633 if (errno == EACCES 4200 filename_to_utf16 (temp, temp_w);
3634 && newname_dev != oldname_dev) 4201 filename_to_utf16 (newname, newname_w);
3635 { 4202 result = _wrename (temp_w, newname_w);
3636 /* The implementation of `rename' on Windows does not return 4203 if (result < 0 && force)
3637 errno = EXDEV when you are moving a directory to a
3638 different storage device (ex. logical disk). It returns
3639 EACCES instead. So here we handle such situations and
3640 return EXDEV. */
3641 DWORD attributes;
3642
3643 if ((attributes = GetFileAttributes (temp)) != -1
3644 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3645 errno = EXDEV;
3646 }
3647 else if (errno == EEXIST)
3648 { 4204 {
3649 if (_chmod (newname, 0666) != 0) 4205 DWORD w32err = GetLastError ();
3650 return result; 4206
3651 if (_unlink (newname) != 0) 4207 if (errno == EACCES
3652 return result; 4208 && newname_dev != oldname_dev)
3653 result = rename (temp, newname); 4209 {
4210 /* The implementation of `rename' on Windows does not return
4211 errno = EXDEV when you are moving a directory to a
4212 different storage device (ex. logical disk). It returns
4213 EACCES instead. So here we handle such situations and
4214 return EXDEV. */
4215 DWORD attributes;
4216
4217 if ((attributes = GetFileAttributesW (temp_w)) != -1
4218 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4219 errno = EXDEV;
4220 }
4221 else if (errno == EEXIST)
4222 {
4223 if (_wchmod (newname_w, 0666) != 0)
4224 return result;
4225 if (_wunlink (newname_w) != 0)
4226 return result;
4227 result = _wrename (temp_w, newname_w);
4228 }
4229 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4230 && is_symlink (temp))
4231 {
4232 /* This is Windows prohibiting the user from creating a
4233 symlink in another place, since that requires
4234 privileges. */
4235 errno = EPERM;
4236 }
3654 } 4237 }
3655 else if (w32err == ERROR_PRIVILEGE_NOT_HELD 4238 }
3656 && is_symlink (temp)) 4239 else
4240 {
4241 char newname_a[MAX_PATH];
4242
4243 if (!have_temp_a)
4244 filename_to_ansi (temp, temp_a);
4245 filename_to_ansi (newname, newname_a);
4246 result = rename (temp_a, newname_a);
4247 if (result < 0 && force)
3657 { 4248 {
3658 /* This is Windows prohibiting the user from creating a 4249 DWORD w32err = GetLastError ();
3659 symlink in another place, since that requires 4250
3660 privileges. */ 4251 if (errno == EACCES
3661 errno = EPERM; 4252 && newname_dev != oldname_dev)
4253 {
4254 DWORD attributes;
4255
4256 if ((attributes = GetFileAttributesA (temp_a)) != -1
4257 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4258 errno = EXDEV;
4259 }
4260 else if (errno == EEXIST)
4261 {
4262 if (_chmod (newname_a, 0666) != 0)
4263 return result;
4264 if (_unlink (newname_a) != 0)
4265 return result;
4266 result = rename (temp_a, newname_a);
4267 }
4268 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4269 && is_symlink (temp))
4270 errno = EPERM;
3662 } 4271 }
3663 } 4272 }
3664 4273
@@ -3674,7 +4283,22 @@ sys_rename (char const *old, char const *new)
3674int 4283int
3675sys_rmdir (const char * path) 4284sys_rmdir (const char * path)
3676{ 4285{
3677 return _rmdir (map_w32_filename (path, NULL)); 4286 path = map_w32_filename (path, NULL);
4287
4288 if (w32_unicode_filenames)
4289 {
4290 wchar_t path_w[MAX_PATH];
4291
4292 filename_to_utf16 (path, path_w);
4293 return _wrmdir (path_w);
4294 }
4295 else
4296 {
4297 char path_a[MAX_PATH];
4298
4299 filename_to_ansi (path, path_a);
4300 return _rmdir (path_a);
4301 }
3678} 4302}
3679 4303
3680int 4304int
@@ -3682,9 +4306,23 @@ sys_unlink (const char * path)
3682{ 4306{
3683 path = map_w32_filename (path, NULL); 4307 path = map_w32_filename (path, NULL);
3684 4308
3685 /* On Unix, unlink works without write permission. */ 4309 if (w32_unicode_filenames)
3686 _chmod (path, 0666); 4310 {
3687 return _unlink (path); 4311 wchar_t path_w[MAX_PATH];
4312
4313 filename_to_utf16 (path, path_w);
4314 /* On Unix, unlink works without write permission. */
4315 _wchmod (path_w, 0666);
4316 return _wunlink (path_w);
4317 }
4318 else
4319 {
4320 char path_a[MAX_PATH];
4321
4322 filename_to_ansi (path, path_a);
4323 _chmod (path_a, 0666);
4324 return _unlink (path_a);
4325 }
3688} 4326}
3689 4327
3690static FILETIME utc_base_ft; 4328static FILETIME utc_base_ft;
@@ -3752,49 +4390,6 @@ convert_from_time_t (time_t time, FILETIME * pft)
3752 pft->dwLowDateTime = tmp.LowPart; 4390 pft->dwLowDateTime = tmp.LowPart;
3753} 4391}
3754 4392
3755#if 0
3756/* No reason to keep this; faking inode values either by hashing or even
3757 using the file index from GetInformationByHandle, is not perfect and
3758 so by default Emacs doesn't use the inode values on Windows.
3759 Instead, we now determine file-truename correctly (except for
3760 possible drive aliasing etc). */
3761
3762/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3763static unsigned
3764hashval (const unsigned char * str)
3765{
3766 unsigned h = 0;
3767 while (*str)
3768 {
3769 h = (h << 4) + *str++;
3770 h ^= (h >> 28);
3771 }
3772 return h;
3773}
3774
3775/* Return the hash value of the canonical pathname, excluding the
3776 drive/UNC header, to get a hopefully unique inode number. */
3777static DWORD
3778generate_inode_val (const char * name)
3779{
3780 char fullname[ MAX_PATH ];
3781 char * p;
3782 unsigned hash;
3783
3784 /* Get the truly canonical filename, if it exists. (Note: this
3785 doesn't resolve aliasing due to subst commands, or recognize hard
3786 links. */
3787 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3788 emacs_abort ();
3789
3790 parse_root (fullname, &p);
3791 /* Normal W32 filesystems are still case insensitive. */
3792 _strlwr (p);
3793 return hashval (p);
3794}
3795
3796#endif
3797
3798static PSECURITY_DESCRIPTOR 4393static PSECURITY_DESCRIPTOR
3799get_file_security_desc_by_handle (HANDLE h) 4394get_file_security_desc_by_handle (HANDLE h)
3800{ 4395{
@@ -4001,18 +4596,21 @@ is_slow_fs (const char *name)
4001} 4596}
4002 4597
4003/* If this is non-zero, the caller wants accurate information about 4598/* If this is non-zero, the caller wants accurate information about
4004 file's owner and group, which could be expensive to get. */ 4599 file's owner and group, which could be expensive to get. dired.c
4600 uses this flag when needed for the job at hand. */
4005int w32_stat_get_owner_group; 4601int w32_stat_get_owner_group;
4006 4602
4007/* MSVC stat function can't cope with UNC names and has other bugs, so 4603/* MSVC stat function can't cope with UNC names and has other bugs, so
4008 replace it with our own. This also allows us to calculate consistent 4604 replace it with our own. This also allows us to calculate consistent
4009 inode values and owner/group without hacks in the main Emacs code. */ 4605 inode values and owner/group without hacks in the main Emacs code,
4606 and support file names encoded in UTF-8. */
4010 4607
4011static int 4608static int
4012stat_worker (const char * path, struct stat * buf, int follow_symlinks) 4609stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4013{ 4610{
4014 char *name, *save_name, *r; 4611 char *name, *save_name, *r;
4015 WIN32_FIND_DATA wfd; 4612 WIN32_FIND_DATAW wfd_w;
4613 WIN32_FIND_DATAA wfd_a;
4016 HANDLE fh; 4614 HANDLE fh;
4017 unsigned __int64 fake_inode = 0; 4615 unsigned __int64 fake_inode = 0;
4018 int permission; 4616 int permission;
@@ -4024,7 +4622,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4024 DWORD access_rights = 0; 4622 DWORD access_rights = 0;
4025 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; 4623 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4026 FILETIME ctime, atime, wtime; 4624 FILETIME ctime, atime, wtime;
4027 int dbcs_p; 4625 wchar_t name_w[MAX_PATH];
4626 char name_a[MAX_PATH];
4028 4627
4029 if (path == NULL || buf == NULL) 4628 if (path == NULL || buf == NULL)
4030 { 4629 {
@@ -4034,11 +4633,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4034 4633
4035 save_name = name = (char *) map_w32_filename (path, &path); 4634 save_name = name = (char *) map_w32_filename (path, &path);
4036 /* Must be valid filename, no wild cards or other invalid 4635 /* Must be valid filename, no wild cards or other invalid
4037 characters. We use _mbspbrk to support multibyte strings that 4636 characters. */
4038 might look to strpbrk as if they included literal *, ?, and other 4637 if (strpbrk (name, "*?|<>\""))
4039 characters mentioned below that are disallowed by Windows
4040 filesystems. */
4041 if (_mbspbrk (name, "*?|<>\""))
4042 { 4638 {
4043 errno = ENOENT; 4639 errno = ENOENT;
4044 return -1; 4640 return -1;
@@ -4089,13 +4685,26 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4089 if (is_windows_9x () != TRUE) 4685 if (is_windows_9x () != TRUE)
4090 access_rights |= READ_CONTROL; 4686 access_rights |= READ_CONTROL;
4091 4687
4092 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING, 4688 if (w32_unicode_filenames)
4093 file_flags, NULL); 4689 {
4094 /* If CreateFile fails with READ_CONTROL, try again with zero as 4690 filename_to_utf16 (name, name_w);
4095 access rights. */ 4691 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4096 if (fh == INVALID_HANDLE_VALUE && access_rights) 4692 file_flags, NULL);
4097 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 4693 /* If CreateFile fails with READ_CONTROL, try again with
4098 file_flags, NULL); 4694 zero as access rights. */
4695 if (fh == INVALID_HANDLE_VALUE && access_rights)
4696 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4697 file_flags, NULL);
4698 }
4699 else
4700 {
4701 filename_to_ansi (name, name_a);
4702 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4703 file_flags, NULL);
4704 if (fh == INVALID_HANDLE_VALUE && access_rights)
4705 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4706 file_flags, NULL);
4707 }
4099 if (fh == INVALID_HANDLE_VALUE) 4708 if (fh == INVALID_HANDLE_VALUE)
4100 goto no_true_file_attributes; 4709 goto no_true_file_attributes;
4101 4710
@@ -4222,7 +4831,6 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4222 did not ask for extra precision, resolving symlinks will fly 4831 did not ask for extra precision, resolving symlinks will fly
4223 in the face of that request, since the user then wants the 4832 in the face of that request, since the user then wants the
4224 lightweight version of the code. */ 4833 lightweight version of the code. */
4225 dbcs_p = max_filename_mbslen () > 1;
4226 rootdir = (path >= save_name + len - 1 4834 rootdir = (path >= save_name + len - 1
4227 && (IS_DIRECTORY_SEP (*path) || *path == 0)); 4835 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4228 4836
@@ -4250,19 +4858,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4250 } 4858 }
4251 else if (rootdir) 4859 else if (rootdir)
4252 { 4860 {
4253 if (!dbcs_p) 4861 if (!IS_DIRECTORY_SEP (name[len-1]))
4254 { 4862 strcat (name, "\\");
4255 if (!IS_DIRECTORY_SEP (name[len-1]))
4256 strcat (name, "\\");
4257 }
4258 else
4259 {
4260 char *end = name + len;
4261 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4262
4263 if (!IS_DIRECTORY_SEP (*n))
4264 strcat (name, "\\");
4265 }
4266 if (GetDriveType (name) < 2) 4863 if (GetDriveType (name) < 2)
4267 { 4864 {
4268 errno = ENOENT; 4865 errno = ENOENT;
@@ -4274,51 +4871,65 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4274 } 4871 }
4275 else 4872 else
4276 { 4873 {
4277 if (!dbcs_p) 4874 int have_wfd = -1;
4278 {
4279 if (IS_DIRECTORY_SEP (name[len-1]))
4280 name[len - 1] = 0;
4281 }
4282 else
4283 {
4284 char *end = name + len;
4285 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4286 4875
4287 if (IS_DIRECTORY_SEP (*n)) 4876 if (IS_DIRECTORY_SEP (name[len-1]))
4288 *n = 0; 4877 name[len - 1] = 0;
4289 }
4290 4878
4291 /* (This is hacky, but helps when doing file completions on 4879 /* (This is hacky, but helps when doing file completions on
4292 network drives.) Optimize by using information available from 4880 network drives.) Optimize by using information available from
4293 active readdir if possible. */ 4881 active readdir if possible. */
4294 len = strlen (dir_pathname); 4882 len = strlen (dir_pathname);
4295 if (!dbcs_p) 4883 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4296 { 4884 len--;
4297 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4298 len--;
4299 }
4300 else
4301 {
4302 char *end = dir_pathname + len;
4303 char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
4304
4305 if (IS_DIRECTORY_SEP (*n))
4306 len--;
4307 }
4308 if (dir_find_handle != INVALID_HANDLE_VALUE 4885 if (dir_find_handle != INVALID_HANDLE_VALUE
4886 && last_dir_find_data != -1
4309 && !(is_a_symlink && follow_symlinks) 4887 && !(is_a_symlink && follow_symlinks)
4310 && strnicmp (save_name, dir_pathname, len) == 0 4888 /* The 2 file-name comparisons below support only ASCII
4889 characters, and will lose (compare not equal) when
4890 the file names include non-ASCII charcaters that are
4891 the same but for the case. However, doing this
4892 properly involves: (a) converting both file names to
4893 UTF-16, (b) lower-casing both names using CharLowerW,
4894 and (c) comparing the results; this would be quite a
4895 bit slower, whereas Plan B is for users who want
4896 lightweight albeit inaccurate version of 'stat'. */
4897 && c_strncasecmp (save_name, dir_pathname, len) == 0
4311 && IS_DIRECTORY_SEP (name[len]) 4898 && IS_DIRECTORY_SEP (name[len])
4312 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0) 4899 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4313 { 4900 {
4901 have_wfd = last_dir_find_data;
4314 /* This was the last entry returned by readdir. */ 4902 /* This was the last entry returned by readdir. */
4315 wfd = dir_find_data; 4903 if (last_dir_find_data == DIR_FIND_DATA_W)
4904 wfd_w = dir_find_data_w;
4905 else
4906 wfd_a = dir_find_data_a;
4316 } 4907 }
4317 else 4908 else
4318 { 4909 {
4319 logon_network_drive (name); 4910 logon_network_drive (name);
4320 4911
4321 fh = FindFirstFile (name, &wfd); 4912 if (w32_unicode_filenames)
4913 {
4914 filename_to_utf16 (name, name_w);
4915 fh = FindFirstFileW (name_w, &wfd_w);
4916 have_wfd = DIR_FIND_DATA_W;
4917 }
4918 else
4919 {
4920 filename_to_ansi (name, name_a);
4921 /* If NAME includes characters not representable by
4922 the current ANSI codepage, filename_to_ansi
4923 usually replaces them with a '?'. We don't want
4924 to let FindFirstFileA interpret those as widlcards,
4925 and "succeed", returning us data from some random
4926 file in the same directory. */
4927 if (_mbspbrk (name_a, "?"))
4928 fh = INVALID_HANDLE_VALUE;
4929 else
4930 fh = FindFirstFileA (name_a, &wfd_a);
4931 have_wfd = DIR_FIND_DATA_A;
4932 }
4322 if (fh == INVALID_HANDLE_VALUE) 4933 if (fh == INVALID_HANDLE_VALUE)
4323 { 4934 {
4324 errno = ENOENT; 4935 errno = ENOENT;
@@ -4328,12 +4939,24 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4328 } 4939 }
4329 /* Note: if NAME is a symlink, the information we get from 4940 /* Note: if NAME is a symlink, the information we get from
4330 FindFirstFile is for the symlink, not its target. */ 4941 FindFirstFile is for the symlink, not its target. */
4331 fattrs = wfd.dwFileAttributes; 4942 if (have_wfd == DIR_FIND_DATA_W)
4332 ctime = wfd.ftCreationTime; 4943 {
4333 atime = wfd.ftLastAccessTime; 4944 fattrs = wfd_w.dwFileAttributes;
4334 wtime = wfd.ftLastWriteTime; 4945 ctime = wfd_w.ftCreationTime;
4335 fs_high = wfd.nFileSizeHigh; 4946 atime = wfd_w.ftLastAccessTime;
4336 fs_low = wfd.nFileSizeLow; 4947 wtime = wfd_w.ftLastWriteTime;
4948 fs_high = wfd_w.nFileSizeHigh;
4949 fs_low = wfd_w.nFileSizeLow;
4950 }
4951 else
4952 {
4953 fattrs = wfd_a.dwFileAttributes;
4954 ctime = wfd_a.ftCreationTime;
4955 atime = wfd_a.ftLastAccessTime;
4956 wtime = wfd_a.ftLastWriteTime;
4957 fs_high = wfd_a.nFileSizeHigh;
4958 fs_low = wfd_a.nFileSizeLow;
4959 }
4337 fake_inode = 0; 4960 fake_inode = 0;
4338 nlinks = 1; 4961 nlinks = 1;
4339 serialnum = volume_info.serialnum; 4962 serialnum = volume_info.serialnum;
@@ -4348,18 +4971,6 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4348 get_file_owner_and_group (NULL, buf); 4971 get_file_owner_and_group (NULL, buf);
4349 } 4972 }
4350 4973
4351#if 0
4352 /* Not sure if there is any point in this. */
4353 if (!NILP (Vw32_generate_fake_inodes))
4354 fake_inode = generate_inode_val (name);
4355 else if (fake_inode == 0)
4356 {
4357 /* For want of something better, try to make everything unique. */
4358 static DWORD gen_num = 0;
4359 fake_inode = ++gen_num;
4360 }
4361#endif
4362
4363 buf->st_ino = fake_inode; 4974 buf->st_ino = fake_inode;
4364 4975
4365 buf->st_dev = serialnum; 4976 buf->st_dev = serialnum;
@@ -4418,7 +5029,7 @@ fstatat (int fd, char const *name, struct stat *st, int flags)
4418 5029
4419 FIXME: Add proper support for fdopendir, fstatat, readlinkat. 5030 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4420 Gnulib does this and can serve as a model. */ 5031 Gnulib does this and can serve as a model. */
4421 char fullname[MAX_PATH]; 5032 char fullname[MAX_UTF8_PATH];
4422 5033
4423 if (fd != AT_FDCWD) 5034 if (fd != AT_FDCWD)
4424 { 5035 {
@@ -4563,13 +5174,32 @@ utime (const char *name, struct utimbuf *times)
4563 times = &deftime; 5174 times = &deftime;
4564 } 5175 }
4565 5176
4566 /* Need write access to set times. */ 5177 if (w32_unicode_filenames)
4567 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES, 5178 {
4568 /* If NAME specifies a directory, FILE_SHARE_DELETE 5179 wchar_t name_utf16[MAX_PATH];
4569 allows other processes to delete files inside it, 5180
4570 while we have the directory open. */ 5181 if (filename_to_utf16 (name, name_utf16) != 0)
4571 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 5182 return -1; /* errno set by filename_to_utf16 */
4572 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 5183
5184 /* Need write access to set times. */
5185 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5186 /* If NAME specifies a directory, FILE_SHARE_DELETE
5187 allows other processes to delete files inside it,
5188 while we have the directory open. */
5189 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5190 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5191 }
5192 else
5193 {
5194 char name_ansi[MAX_PATH];
5195
5196 if (filename_to_ansi (name, name_ansi) != 0)
5197 return -1; /* errno set by filename_to_ansi */
5198
5199 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5200 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5201 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5202 }
4573 if (fh != INVALID_HANDLE_VALUE) 5203 if (fh != INVALID_HANDLE_VALUE)
4574 { 5204 {
4575 convert_from_time_t (times->actime, &atime); 5205 convert_from_time_t (times->actime, &atime);
@@ -4584,7 +5214,31 @@ utime (const char *name, struct utimbuf *times)
4584 } 5214 }
4585 else 5215 else
4586 { 5216 {
4587 errno = EINVAL; 5217 DWORD err = GetLastError ();
5218
5219 switch (err)
5220 {
5221 case ERROR_FILE_NOT_FOUND:
5222 case ERROR_PATH_NOT_FOUND:
5223 case ERROR_INVALID_DRIVE:
5224 case ERROR_BAD_NETPATH:
5225 case ERROR_DEV_NOT_EXIST:
5226 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5227 file name includes ?s, i.e. translation to ANSI failed. */
5228 case ERROR_INVALID_NAME:
5229 errno = ENOENT;
5230 break;
5231 case ERROR_TOO_MANY_OPEN_FILES:
5232 errno = ENFILE;
5233 break;
5234 case ERROR_ACCESS_DENIED:
5235 case ERROR_SHARING_VIOLATION:
5236 errno = EACCES;
5237 break;
5238 default:
5239 errno = EINVAL;
5240 break;
5241 }
4588 return -1; 5242 return -1;
4589 } 5243 }
4590 return 0; 5244 return 0;
@@ -4599,10 +5253,9 @@ utime (const char *name, struct utimbuf *times)
4599int 5253int
4600symlink (char const *filename, char const *linkname) 5254symlink (char const *filename, char const *linkname)
4601{ 5255{
4602 char linkfn[MAX_PATH], *tgtfn; 5256 char linkfn[MAX_UTF8_PATH], *tgtfn;
4603 DWORD flags = 0; 5257 DWORD flags = 0;
4604 int dir_access, filename_ends_in_slash; 5258 int dir_access, filename_ends_in_slash;
4605 int dbcs_p;
4606 5259
4607 /* Diagnostics follows Posix as much as possible. */ 5260 /* Diagnostics follows Posix as much as possible. */
4608 if (filename == NULL || linkname == NULL) 5261 if (filename == NULL || linkname == NULL)
@@ -4615,7 +5268,7 @@ symlink (char const *filename, char const *linkname)
4615 errno = ENOENT; 5268 errno = ENOENT;
4616 return -1; 5269 return -1;
4617 } 5270 }
4618 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH) 5271 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
4619 { 5272 {
4620 errno = ENAMETOOLONG; 5273 errno = ENAMETOOLONG;
4621 return -1; 5274 return -1;
@@ -4628,8 +5281,6 @@ symlink (char const *filename, char const *linkname)
4628 return -1; 5281 return -1;
4629 } 5282 }
4630 5283
4631 dbcs_p = max_filename_mbslen () > 1;
4632
4633 /* Note: since empty FILENAME was already rejected, we can safely 5284 /* Note: since empty FILENAME was already rejected, we can safely
4634 refer to FILENAME[1]. */ 5285 refer to FILENAME[1]. */
4635 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) 5286 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
@@ -4641,24 +5292,11 @@ symlink (char const *filename, char const *linkname)
4641 directory where the Emacs process runs. Note that 5292 directory where the Emacs process runs. Note that
4642 make-symbolic-link always makes sure LINKNAME is a fully 5293 make-symbolic-link always makes sure LINKNAME is a fully
4643 expanded file name. */ 5294 expanded file name. */
4644 char tem[MAX_PATH]; 5295 char tem[MAX_UTF8_PATH];
4645 char *p = linkfn + strlen (linkfn); 5296 char *p = linkfn + strlen (linkfn);
4646 5297
4647 if (!dbcs_p) 5298 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4648 { 5299 p--;
4649 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4650 p--;
4651 }
4652 else
4653 {
4654 char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
4655
4656 while (p > linkfn && !IS_ANY_SEP (*p1))
4657 {
4658 p = p1;
4659 p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
4660 }
4661 }
4662 if (p > linkfn) 5300 if (p > linkfn)
4663 strncpy (tem, linkfn, p - linkfn); 5301 strncpy (tem, linkfn, p - linkfn);
4664 tem[p - linkfn] = '\0'; 5302 tem[p - linkfn] = '\0';
@@ -4673,15 +5311,7 @@ symlink (char const *filename, char const *linkname)
4673 exist, but ends in a slash, we create a symlink to directory. If 5311 exist, but ends in a slash, we create a symlink to directory. If
4674 FILENAME exists and is a directory, we always create a symlink to 5312 FILENAME exists and is a directory, we always create a symlink to
4675 directory. */ 5313 directory. */
4676 if (!dbcs_p) 5314 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4677 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4678 else
4679 {
4680 const char *end = filename + strlen (filename);
4681 const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
4682
4683 filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
4684 }
4685 if (dir_access == 0 || filename_ends_in_slash) 5315 if (dir_access == 0 || filename_ends_in_slash)
4686 flags = SYMBOLIC_LINK_FLAG_DIRECTORY; 5316 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4687 5317
@@ -4751,10 +5381,23 @@ static int
4751is_symlink (const char *filename) 5381is_symlink (const char *filename)
4752{ 5382{
4753 DWORD attrs; 5383 DWORD attrs;
4754 WIN32_FIND_DATA wfd; 5384 wchar_t filename_w[MAX_PATH];
5385 char filename_a[MAX_PATH];
5386 WIN32_FIND_DATAW wfdw;
5387 WIN32_FIND_DATAA wfda;
4755 HANDLE fh; 5388 HANDLE fh;
5389 int attrs_mean_symlink;
4756 5390
4757 attrs = GetFileAttributes (filename); 5391 if (w32_unicode_filenames)
5392 {
5393 filename_to_utf16 (filename, filename_w);
5394 attrs = GetFileAttributesW (filename_w);
5395 }
5396 else
5397 {
5398 filename_to_ansi (filename, filename_a);
5399 attrs = GetFileAttributesA (filename_a);
5400 }
4758 if (attrs == -1) 5401 if (attrs == -1)
4759 { 5402 {
4760 DWORD w32err = GetLastError (); 5403 DWORD w32err = GetLastError ();
@@ -4777,12 +5420,30 @@ is_symlink (const char *filename)
4777 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) 5420 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4778 return 0; 5421 return 0;
4779 logon_network_drive (filename); 5422 logon_network_drive (filename);
4780 fh = FindFirstFile (filename, &wfd); 5423 if (w32_unicode_filenames)
5424 {
5425 fh = FindFirstFileW (filename_w, &wfdw);
5426 attrs_mean_symlink =
5427 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5428 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5429 }
5430 else if (_mbspbrk (filename_a, "?"))
5431 {
5432 /* filename_to_ansi failed to convert the file name. */
5433 errno = ENOENT;
5434 return 0;
5435 }
5436 else
5437 {
5438 fh = FindFirstFileA (filename_a, &wfda);
5439 attrs_mean_symlink =
5440 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5441 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5442 }
4781 if (fh == INVALID_HANDLE_VALUE) 5443 if (fh == INVALID_HANDLE_VALUE)
4782 return 0; 5444 return 0;
4783 FindClose (fh); 5445 FindClose (fh);
4784 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 5446 return attrs_mean_symlink;
4785 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4786} 5447}
4787 5448
4788/* If NAME identifies a symbolic link, copy into BUF the file name of 5449/* If NAME identifies a symbolic link, copy into BUF the file name of
@@ -4799,6 +5460,7 @@ readlink (const char *name, char *buf, size_t buf_size)
4799 int restore_privs = 0; 5460 int restore_privs = 0;
4800 HANDLE sh; 5461 HANDLE sh;
4801 ssize_t retval; 5462 ssize_t retval;
5463 char resolved[MAX_UTF8_PATH];
4802 5464
4803 if (name == NULL) 5465 if (name == NULL)
4804 { 5466 {
@@ -4813,7 +5475,7 @@ readlink (const char *name, char *buf, size_t buf_size)
4813 5475
4814 path = map_w32_filename (name, NULL); 5476 path = map_w32_filename (name, NULL);
4815 5477
4816 if (strlen (path) > MAX_PATH) 5478 if (strlen (path) > MAX_UTF8_PATH)
4817 { 5479 {
4818 errno = ENAMETOOLONG; 5480 errno = ENAMETOOLONG;
4819 return -1; 5481 return -1;
@@ -4843,9 +5505,26 @@ readlink (const char *name, char *buf, size_t buf_size)
4843 e.g. 'C:\Users\All Users', GENERIC_READ fails with 5505 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4844 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file 5506 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4845 and directory symlinks. */ 5507 and directory symlinks. */
4846 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING, 5508 if (w32_unicode_filenames)
4847 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 5509 {
4848 NULL); 5510 wchar_t path_w[MAX_PATH];
5511
5512 filename_to_utf16 (path, path_w);
5513 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5514 FILE_FLAG_OPEN_REPARSE_POINT
5515 | FILE_FLAG_BACKUP_SEMANTICS,
5516 NULL);
5517 }
5518 else
5519 {
5520 char path_a[MAX_PATH];
5521
5522 filename_to_ansi (path, path_a);
5523 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5524 FILE_FLAG_OPEN_REPARSE_POINT
5525 | FILE_FLAG_BACKUP_SEMANTICS,
5526 NULL);
5527 }
4849 if (sh != INVALID_HANDLE_VALUE) 5528 if (sh != INVALID_HANDLE_VALUE)
4850 { 5529 {
4851 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; 5530 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
@@ -4864,89 +5543,27 @@ readlink (const char *name, char *buf, size_t buf_size)
4864 reparse_data, then convert it to multibyte encoding in 5543 reparse_data, then convert it to multibyte encoding in
4865 the current locale's codepage. */ 5544 the current locale's codepage. */
4866 WCHAR *lwname; 5545 WCHAR *lwname;
4867 BYTE lname[MAX_PATH]; 5546 size_t lname_size;
4868 USHORT lname_len;
4869 USHORT lwname_len = 5547 USHORT lwname_len =
4870 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength; 5548 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4871 WCHAR *lwname_src = 5549 WCHAR *lwname_src =
4872 reparse_data->SymbolicLinkReparseBuffer.PathBuffer 5550 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4873 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); 5551 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4874 /* This updates file_name_codepage which we need below. */ 5552 size_t size_to_copy = buf_size;
4875 int dbcs_p = max_filename_mbslen () > 1;
4876 5553
4877 /* According to MSDN, PrintNameLength does not include the 5554 /* According to MSDN, PrintNameLength does not include the
4878 terminating null character. */ 5555 terminating null character. */
4879 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR)); 5556 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4880 memcpy (lwname, lwname_src, lwname_len); 5557 memcpy (lwname, lwname_src, lwname_len);
4881 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */ 5558 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4882 5559 filename_from_utf16 (lwname, resolved);
4883 lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1, 5560 dostounix_filename (resolved);
4884 lname, MAX_PATH, NULL, NULL); 5561 lname_size = strlen (resolved) + 1;
4885 if (!lname_len) 5562 if (lname_size <= buf_size)
4886 { 5563 size_to_copy = lname_size;
4887 /* WideCharToMultiByte failed. */ 5564 strncpy (buf, resolved, size_to_copy);
4888 DWORD w32err1 = GetLastError (); 5565 /* Success! */
4889 5566 retval = size_to_copy;
4890 switch (w32err1)
4891 {
4892 case ERROR_INSUFFICIENT_BUFFER:
4893 errno = ENAMETOOLONG;
4894 break;
4895 case ERROR_INVALID_PARAMETER:
4896 errno = EFAULT;
4897 break;
4898 case ERROR_NO_UNICODE_TRANSLATION:
4899 errno = ENOENT;
4900 break;
4901 default:
4902 errno = EINVAL;
4903 break;
4904 }
4905 }
4906 else
4907 {
4908 size_t size_to_copy = buf_size;
4909 BYTE *p = lname, *p2;
4910 BYTE *pend = p + lname_len;
4911
4912 /* Normalize like dostounix_filename does, but we don't
4913 want to assume that lname is null-terminated. */
4914 if (dbcs_p)
4915 p2 = CharNextExA (file_name_codepage, p, 0);
4916 else
4917 p2 = p + 1;
4918 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
4919 {
4920 *p += 'a' - 'A';
4921 p += 2;
4922 }
4923 while (p <= pend)
4924 {
4925 if (*p == '\\')
4926 *p = '/';
4927 if (dbcs_p)
4928 {
4929 p = CharNextExA (file_name_codepage, p, 0);
4930 /* CharNextExA doesn't advance at null character. */
4931 if (!*p)
4932 break;
4933 }
4934 else
4935 ++p;
4936 }
4937 /* Testing for null-terminated LNAME is paranoia:
4938 WideCharToMultiByte should always return a
4939 null-terminated string when its 4th argument is -1
4940 and its 3rd argument is null-terminated (which they
4941 are, see above). */
4942 if (lname[lname_len - 1] == '\0')
4943 lname_len--;
4944 if (lname_len <= buf_size)
4945 size_to_copy = lname_len;
4946 strncpy (buf, lname, size_to_copy);
4947 /* Success! */
4948 retval = size_to_copy;
4949 }
4950 } 5567 }
4951 CloseHandle (sh); 5568 CloseHandle (sh);
4952 } 5569 }
@@ -4985,7 +5602,7 @@ readlinkat (int fd, char const *name, char *buffer,
4985{ 5602{
4986 /* Rely on a hack: an open directory is modeled as file descriptor 0, 5603 /* Rely on a hack: an open directory is modeled as file descriptor 0,
4987 as in fstatat. FIXME: Add proper support for readlinkat. */ 5604 as in fstatat. FIXME: Add proper support for readlinkat. */
4988 char fullname[MAX_PATH]; 5605 char fullname[MAX_UTF8_PATH];
4989 5606
4990 if (fd != AT_FDCWD) 5607 if (fd != AT_FDCWD)
4991 { 5608 {
@@ -5024,41 +5641,45 @@ readlinkat (int fd, char const *name, char *buffer,
5024static char * 5641static char *
5025chase_symlinks (const char *file) 5642chase_symlinks (const char *file)
5026{ 5643{
5027 static char target[MAX_PATH]; 5644 static char target[MAX_UTF8_PATH];
5028 char link[MAX_PATH]; 5645 char link[MAX_UTF8_PATH];
5646 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5647 char target_a[MAX_PATH], link_a[MAX_PATH];
5029 ssize_t res, link_len; 5648 ssize_t res, link_len;
5030 int loop_count = 0; 5649 int loop_count = 0;
5031 int dbcs_p;
5032 5650
5033 if (is_windows_9x () == TRUE || !is_symlink (file)) 5651 if (is_windows_9x () == TRUE || !is_symlink (file))
5034 return (char *)file; 5652 return (char *)file;
5035 5653
5036 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) 5654 if (w32_unicode_filenames)
5037 return (char *)file; 5655 {
5656 wchar_t file_w[MAX_PATH];
5657
5658 filename_to_utf16 (file, file_w);
5659 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5660 return (char *)file;
5661 filename_from_utf16 (link_w, link);
5662 }
5663 else
5664 {
5665 char file_a[MAX_PATH];
5666
5667 filename_to_ansi (file, file_a);
5668 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5669 return (char *)file;
5670 filename_from_ansi (link_a, link);
5671 }
5672 link_len = strlen (link);
5038 5673
5039 dbcs_p = max_filename_mbslen () > 1;
5040 target[0] = '\0'; 5674 target[0] = '\0';
5041 do { 5675 do {
5042 5676
5043 /* Remove trailing slashes, as we want to resolve the last 5677 /* Remove trailing slashes, as we want to resolve the last
5044 non-trivial part of the link name. */ 5678 non-trivial part of the link name. */
5045 if (!dbcs_p) 5679 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5046 { 5680 link[link_len--] = '\0';
5047 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5048 link[link_len--] = '\0';
5049 }
5050 else if (link_len > 3)
5051 {
5052 char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
5053 5681
5054 while (n >= link + 2 && IS_DIRECTORY_SEP (*n)) 5682 res = readlink (link, target, MAX_UTF8_PATH);
5055 {
5056 n[1] = '\0';
5057 n = CharPrevExA (file_name_codepage, link, n, 0);
5058 }
5059 }
5060
5061 res = readlink (link, target, MAX_PATH);
5062 if (res > 0) 5683 if (res > 0)
5063 { 5684 {
5064 target[res] = '\0'; 5685 target[res] = '\0';
@@ -5069,27 +5690,28 @@ chase_symlinks (const char *file)
5069 the symlink, then copy the result back to target. */ 5690 the symlink, then copy the result back to target. */
5070 char *p = link + link_len; 5691 char *p = link + link_len;
5071 5692
5072 if (!dbcs_p) 5693 while (p > link && !IS_ANY_SEP (p[-1]))
5073 { 5694 p--;
5074 while (p > link && !IS_ANY_SEP (p[-1]))
5075 p--;
5076 }
5077 else
5078 {
5079 char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
5080
5081 while (p > link && !IS_ANY_SEP (*p1))
5082 {
5083 p = p1;
5084 p1 = CharPrevExA (file_name_codepage, link, p1, 0);
5085 }
5086 }
5087 strcpy (p, target); 5695 strcpy (p, target);
5088 strcpy (target, link); 5696 strcpy (target, link);
5089 } 5697 }
5090 /* Resolve any "." and ".." to get a fully-qualified file name 5698 /* Resolve any "." and ".." to get a fully-qualified file name
5091 in link[] again. */ 5699 in link[] again. */
5092 link_len = GetFullPathName (target, MAX_PATH, link, NULL); 5700 if (w32_unicode_filenames)
5701 {
5702 filename_to_utf16 (target, target_w);
5703 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5704 if (link_len > 0)
5705 filename_from_utf16 (link_w, link);
5706 }
5707 else
5708 {
5709 filename_to_ansi (target, target_a);
5710 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5711 if (link_len > 0)
5712 filename_from_ansi (link_a, link);
5713 }
5714 link_len = strlen (link);
5093 } 5715 }
5094 } while (res > 0 && link_len > 0 && ++loop_count <= 100); 5716 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5095 5717
@@ -5206,7 +5828,11 @@ acl_get_file (const char *fname, acl_type_t type)
5206 } 5828 }
5207 } 5829 }
5208 else if (err == ERROR_FILE_NOT_FOUND 5830 else if (err == ERROR_FILE_NOT_FOUND
5209 || err == ERROR_PATH_NOT_FOUND) 5831 || err == ERROR_PATH_NOT_FOUND
5832 /* ERROR_INVALID_NAME is what we get if
5833 w32-unicode-filenames is nil and the file cannot
5834 be encoded in the current ANSI codepage. */
5835 || err == ERROR_INVALID_NAME)
5210 errno = ENOENT; 5836 errno = ENOENT;
5211 else 5837 else
5212 errno = EIO; 5838 errno = EIO;
@@ -5284,7 +5910,7 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5284 5910
5285 e = errno; 5911 e = errno;
5286 errno = 0; 5912 errno = 0;
5287 if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl)) 5913 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
5288 { 5914 {
5289 err = GetLastError (); 5915 err = GetLastError ();
5290 5916
@@ -5317,7 +5943,12 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5317 acl_free (current_acl); 5943 acl_free (current_acl);
5318 } 5944 }
5319 } 5945 }
5320 else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) 5946 else if (err == ERROR_FILE_NOT_FOUND
5947 || err == ERROR_PATH_NOT_FOUND
5948 /* ERROR_INVALID_NAME is what we get if
5949 w32-unicode-filenames is nil and the file cannot be
5950 encoded in the current ANSI codepage. */
5951 || err == ERROR_INVALID_NAME)
5321 errno = ENOENT; 5952 errno = ENOENT;
5322 else 5953 else
5323 errno = EACCES; 5954 errno = EACCES;
@@ -5350,7 +5981,7 @@ careadlinkat (int fd, char const *filename,
5350 struct allocator const *alloc, 5981 struct allocator const *alloc,
5351 ssize_t (*preadlinkat) (int, char const *, char *, size_t)) 5982 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
5352{ 5983{
5353 char linkname[MAX_PATH]; 5984 char linkname[MAX_UTF8_PATH];
5354 ssize_t link_size; 5985 ssize_t link_size;
5355 5986
5356 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); 5987 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
@@ -7753,7 +8384,7 @@ sys_localtime (const time_t *t)
7753HMODULE 8384HMODULE
7754w32_delayed_load (Lisp_Object library_id) 8385w32_delayed_load (Lisp_Object library_id)
7755{ 8386{
7756 HMODULE library_dll = NULL; 8387 HMODULE dll_handle = NULL;
7757 8388
7758 CHECK_SYMBOL (library_id); 8389 CHECK_SYMBOL (library_id);
7759 8390
@@ -7766,26 +8397,56 @@ w32_delayed_load (Lisp_Object library_id)
7766 if (CONSP (dlls)) 8397 if (CONSP (dlls))
7767 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls)) 8398 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
7768 { 8399 {
7769 CHECK_STRING_CAR (dlls); 8400 Lisp_Object dll = XCAR (dlls);
7770 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls))))) 8401 char name[MAX_UTF8_PATH];
7771 { 8402 DWORD res = -1;
7772 char name[MAX_PATH]; 8403
7773 DWORD len; 8404 CHECK_STRING (dll);
7774 8405 dll = ENCODE_FILE (dll);
7775 len = GetModuleFileNameA (library_dll, name, sizeof (name)); 8406 if (w32_unicode_filenames)
7776 found = Fcons (XCAR (dlls), 8407 {
7777 (len > 0) 8408 wchar_t name_w[MAX_PATH];
7778 /* Possibly truncated */ 8409
7779 ? make_specified_string (name, -1, len, 1) 8410 filename_to_utf16 (SSDATA (dll), name_w);
7780 : Qnil); 8411 dll_handle = LoadLibraryW (name_w);
7781 break; 8412 if (dll_handle)
7782 } 8413 {
7783 } 8414 res = GetModuleFileNameW (dll_handle, name_w,
8415 sizeof (name_w));
8416 if (res > 0)
8417 filename_from_utf16 (name_w, name);
8418 }
8419 }
8420 else
8421 {
8422 char name_a[MAX_PATH];
8423
8424 filename_to_ansi (SSDATA (dll), name_a);
8425 dll_handle = LoadLibraryA (name_a);
8426 if (dll_handle)
8427 {
8428 res = GetModuleFileNameA (dll_handle, name_a,
8429 sizeof (name_a));
8430 if (res > 0)
8431 filename_from_ansi (name_a, name);
8432 }
8433 }
8434 if (dll_handle)
8435 {
8436 ptrdiff_t len = strlen (name);
8437 found = Fcons (dll,
8438 (res > 0)
8439 /* Possibly truncated */
8440 ? make_specified_string (name, -1, len, 1)
8441 : Qnil);
8442 break;
8443 }
8444 }
7784 8445
7785 Fput (library_id, QCloaded_from, found); 8446 Fput (library_id, QCloaded_from, found);
7786 } 8447 }
7787 8448
7788 return library_dll; 8449 return dll_handle;
7789} 8450}
7790 8451
7791 8452
@@ -7804,6 +8465,12 @@ check_windows_init_file (void)
7804 Lisp_Object init_file; 8465 Lisp_Object init_file;
7805 int fd; 8466 int fd;
7806 8467
8468 /* Implementation note: this function runs early during Emacs
8469 startup, before startup.el is run. So Vload_path is still in
8470 its initial unibyte form, but it holds UTF-8 encoded file
8471 names, since init_callproc was already called. So we do not
8472 need to ENCODE_FILE here, but we do need to convert the file
8473 names from UTF-8 to ANSI. */
7807 init_file = build_string ("term/w32-win"); 8474 init_file = build_string ("term/w32-win");
7808 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil); 8475 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
7809 if (fd < 0) 8476 if (fd < 0)
@@ -7814,6 +8481,8 @@ check_windows_init_file (void)
7814 char *buffer = alloca (1024 8481 char *buffer = alloca (1024
7815 + strlen (init_file_name) 8482 + strlen (init_file_name)
7816 + strlen (load_path)); 8483 + strlen (load_path));
8484 char *msg = buffer;
8485 int needed;
7817 8486
7818 sprintf (buffer, 8487 sprintf (buffer,
7819 "The Emacs Windows initialization file \"%s.el\" " 8488 "The Emacs Windows initialization file \"%s.el\" "
@@ -7825,8 +8494,27 @@ check_windows_init_file (void)
7825 "not unpacked properly.\nSee the README.W32 file in the " 8494 "not unpacked properly.\nSee the README.W32 file in the "
7826 "top-level Emacs directory for more information.", 8495 "top-level Emacs directory for more information.",
7827 init_file_name, load_path); 8496 init_file_name, load_path);
8497 needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8498 -1, NULL, 0);
8499 if (needed > 0)
8500 {
8501 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8502
8503 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8504 msg_w, needed);
8505 needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8506 NULL, 0, NULL, NULL);
8507 if (needed > 0)
8508 {
8509 char *msg_a = alloca (needed + 1);
8510
8511 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8512 NULL, NULL);
8513 msg = msg_a;
8514 }
8515 }
7828 MessageBox (NULL, 8516 MessageBox (NULL,
7829 buffer, 8517 msg,
7830 "Emacs Abort Dialog", 8518 "Emacs Abort Dialog",
7831 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); 8519 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
7832 /* Use the low-level system abort. */ 8520 /* Use the low-level system abort. */
@@ -8002,7 +8690,8 @@ globals_of_w32 (void)
8002 g_b_init_get_sid_sub_authority = 0; 8690 g_b_init_get_sid_sub_authority = 0;
8003 g_b_init_get_sid_sub_authority_count = 0; 8691 g_b_init_get_sid_sub_authority_count = 0;
8004 g_b_init_get_security_info = 0; 8692 g_b_init_get_security_info = 0;
8005 g_b_init_get_file_security = 0; 8693 g_b_init_get_file_security_w = 0;
8694 g_b_init_get_file_security_a = 0;
8006 g_b_init_get_security_descriptor_owner = 0; 8695 g_b_init_get_security_descriptor_owner = 0;
8007 g_b_init_get_security_descriptor_group = 0; 8696 g_b_init_get_security_descriptor_group = 0;
8008 g_b_init_is_valid_sid = 0; 8697 g_b_init_is_valid_sid = 0;
@@ -8021,12 +8710,14 @@ globals_of_w32 (void)
8021 g_b_init_get_length_sid = 0; 8710 g_b_init_get_length_sid = 0;
8022 g_b_init_get_native_system_info = 0; 8711 g_b_init_get_native_system_info = 0;
8023 g_b_init_get_system_times = 0; 8712 g_b_init_get_system_times = 0;
8024 g_b_init_create_symbolic_link = 0; 8713 g_b_init_create_symbolic_link_w = 0;
8714 g_b_init_create_symbolic_link_a = 0;
8025 g_b_init_get_security_descriptor_dacl = 0; 8715 g_b_init_get_security_descriptor_dacl = 0;
8026 g_b_init_convert_sd_to_sddl = 0; 8716 g_b_init_convert_sd_to_sddl = 0;
8027 g_b_init_convert_sddl_to_sd = 0; 8717 g_b_init_convert_sddl_to_sd = 0;
8028 g_b_init_is_valid_security_descriptor = 0; 8718 g_b_init_is_valid_security_descriptor = 0;
8029 g_b_init_set_file_security = 0; 8719 g_b_init_set_file_security_w = 0;
8720 g_b_init_set_file_security_a = 0;
8030 g_b_init_get_adapters_info = 0; 8721 g_b_init_get_adapters_info = 0;
8031 num_of_processors = 0; 8722 num_of_processors = 0;
8032 /* The following sets a handler for shutdown notifications for 8723 /* The following sets a handler for shutdown notifications for
@@ -8040,6 +8731,14 @@ globals_of_w32 (void)
8040 8731
8041 /* Reset, in case it has some value inherited from dump time. */ 8732 /* Reset, in case it has some value inherited from dump time. */
8042 w32_stat_get_owner_group = 0; 8733 w32_stat_get_owner_group = 0;
8734
8735 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8736 (a.k.a. "wide") APIs to invoke functions that accept file
8737 names. */
8738 if (is_windows_9x ())
8739 w32_unicode_filenames = 0;
8740 else
8741 w32_unicode_filenames = 1;
8043} 8742}
8044 8743
8045/* For make-serial-process */ 8744/* For make-serial-process */
diff --git a/src/w32.h b/src/w32.h
index 32d0fdbe3cf..cca95855a78 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -103,12 +103,6 @@ typedef struct _child_process
103 OVERLAPPED ovl_read; 103 OVERLAPPED ovl_read;
104 /* Used for async write operations on serial comm ports. */ 104 /* Used for async write operations on serial comm ports. */
105 OVERLAPPED ovl_write; 105 OVERLAPPED ovl_write;
106 /* Input file, if any, for this subprocess. Should only be non-NULL
107 for async subprocesses. */
108 char *input_file;
109 /* If non-zero, the subprocess input file is temporary and should be
110 deleted when the subprocess exits. */
111 int pending_deletion;
112} child_process; 106} child_process;
113 107
114#define MAXDESC FD_SETSIZE 108#define MAXDESC FD_SETSIZE
@@ -152,6 +146,9 @@ extern int w32_valid_pointer_p (void *, int);
152/* Get long (aka "true") form of file name, if it exists. */ 146/* Get long (aka "true") form of file name, if it exists. */
153extern BOOL w32_get_long_filename (char * name, char * buf, int size); 147extern BOOL w32_get_long_filename (char * name, char * buf, int size);
154 148
149/* Get the short (a.k.a. "8+3") form of a file name. */
150extern unsigned int w32_get_short_filename (char *, char *, int);
151
155/* Prepare our standard handles for proper inheritance by child processes. */ 152/* Prepare our standard handles for proper inheritance by child processes. */
156extern void prepare_standard_handles (int in, int out, 153extern void prepare_standard_handles (int in, int out,
157 int err, HANDLE handles[4]); 154 int err, HANDLE handles[4]);
@@ -181,8 +178,14 @@ extern void init_environment (char **);
181extern void check_windows_init_file (void); 178extern void check_windows_init_file (void);
182extern void syms_of_ntproc (void); 179extern void syms_of_ntproc (void);
183extern void syms_of_ntterm (void); 180extern void syms_of_ntterm (void);
184extern void dostounix_filename (register char *, int); 181extern void dostounix_filename (register char *);
185extern void unixtodos_filename (register char *); 182extern void unixtodos_filename (register char *);
183extern int filename_from_ansi (const char *, char *);
184extern int filename_to_ansi (const char *, char *);
185extern int filename_from_utf16 (const wchar_t *, char *);
186extern int filename_to_utf16 (const char *, wchar_t *);
187extern Lisp_Object ansi_encode_filename (Lisp_Object);
188
186extern BOOL init_winsock (int load_now); 189extern BOOL init_winsock (int load_now);
187extern void srandom (int); 190extern void srandom (int);
188extern int random (void); 191extern int random (void);
@@ -194,14 +197,10 @@ extern int pipe2 (int *, int);
194extern void set_process_dir (char *); 197extern void set_process_dir (char *);
195extern int sys_spawnve (int, char *, char **, char **); 198extern int sys_spawnve (int, char *, char **, char **);
196extern void register_child (pid_t, int); 199extern void register_child (pid_t, int);
197extern void record_infile (pid_t, char *);
198extern void record_pending_deletion (char *);
199 200
200extern void sys_sleep (int); 201extern void sys_sleep (int);
201extern int sys_link (const char *, const char *); 202extern int sys_link (const char *, const char *);
202 203
203
204
205#ifdef HAVE_GNUTLS 204#ifdef HAVE_GNUTLS
206#include <gnutls/gnutls.h> 205#include <gnutls/gnutls.h>
207 206
diff --git a/src/w32fns.c b/src/w32fns.c
index 79011f9afc2..e5d899d8a15 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -51,6 +51,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
51 51
52#ifdef WINDOWSNT 52#ifdef WINDOWSNT
53#include "w32heap.h" 53#include "w32heap.h"
54#include <mbstring.h>
54#endif /* WINDOWSNT */ 55#endif /* WINDOWSNT */
55 56
56#if CYGWIN 57#if CYGWIN
@@ -6305,18 +6306,31 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6305{ 6306{
6306 if (msg == WM_NOTIFY) 6307 if (msg == WM_NOTIFY)
6307 { 6308 {
6309 OFNOTIFYW * notify_w = (OFNOTIFYW *)lParam;
6310 OFNOTIFYA * notify_a = (OFNOTIFYA *)lParam;
6311 int dropdown_changed;
6312 int dir_index;
6308#ifdef NTGUI_UNICODE 6313#ifdef NTGUI_UNICODE
6309 OFNOTIFYW * notify = (OFNOTIFYW *)lParam; 6314 const int use_unicode = 1;
6310#else /* !NTGUI_UNICODE */ 6315#else /* !NTGUI_UNICODE */
6311 OFNOTIFYA * notify = (OFNOTIFYA *)lParam; 6316 int use_unicode = w32_unicode_filenames;
6312#endif /* NTGUI_UNICODE */ 6317#endif /* NTGUI_UNICODE */
6318
6313 /* Detect when the Filter dropdown is changed. */ 6319 /* Detect when the Filter dropdown is changed. */
6314 if (notify->hdr.code == CDN_TYPECHANGE 6320 if (use_unicode)
6315 || notify->hdr.code == CDN_INITDONE) 6321 dropdown_changed =
6322 notify_w->hdr.code == CDN_TYPECHANGE
6323 || notify_w->hdr.code == CDN_INITDONE;
6324 else
6325 dropdown_changed =
6326 notify_a->hdr.code == CDN_TYPECHANGE
6327 || notify_a->hdr.code == CDN_INITDONE;
6328 if (dropdown_changed)
6316 { 6329 {
6317 HWND dialog = GetParent (hwnd); 6330 HWND dialog = GetParent (hwnd);
6318 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD); 6331 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
6319 HWND list = GetDlgItem (dialog, FILE_NAME_LIST); 6332 HWND list = GetDlgItem (dialog, FILE_NAME_LIST);
6333 int hdr_code;
6320 6334
6321 /* At least on Windows 7, the above attempt to get the window handle 6335 /* At least on Windows 7, the above attempt to get the window handle
6322 to the File Name Text Field fails. The following code does the 6336 to the File Name Text Field fails. The following code does the
@@ -6334,10 +6348,24 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6334 } 6348 }
6335 6349
6336 /* Directories is in index 2. */ 6350 /* Directories is in index 2. */
6337 if (notify->lpOFN->nFilterIndex == 2) 6351 if (use_unicode)
6352 {
6353 dir_index = notify_w->lpOFN->nFilterIndex;
6354 hdr_code = notify_w->hdr.code;
6355 }
6356 else
6338 { 6357 {
6339 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD, 6358 dir_index = notify_a->lpOFN->nFilterIndex;
6340 GUISTR ("Current Directory")); 6359 hdr_code = notify_a->hdr.code;
6360 }
6361 if (dir_index == 2)
6362 {
6363 if (use_unicode)
6364 SendMessageW (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
6365 (LPARAM)L"Current Directory");
6366 else
6367 SendMessageA (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
6368 (LPARAM)"Current Directory");
6341 EnableWindow (edit_control, FALSE); 6369 EnableWindow (edit_control, FALSE);
6342 /* Note that at least on Windows 7, the above call to EnableWindow 6370 /* Note that at least on Windows 7, the above call to EnableWindow
6343 disables the window that would ordinarily have focus. If we 6371 disables the window that would ordinarily have focus. If we
@@ -6345,16 +6373,21 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6345 no man's land and the user will be unable to tab through the 6373 no man's land and the user will be unable to tab through the
6346 dialog box (pressing tab will only result in a beep). 6374 dialog box (pressing tab will only result in a beep).
6347 Avoid that problem by setting focus to the list here. */ 6375 Avoid that problem by setting focus to the list here. */
6348 if (notify->hdr.code == CDN_INITDONE) 6376 if (hdr_code == CDN_INITDONE)
6349 SetFocus (list); 6377 SetFocus (list);
6350 } 6378 }
6351 else 6379 else
6352 { 6380 {
6353 /* Don't override default filename on init done. */ 6381 /* Don't override default filename on init done. */
6354 if (notify->hdr.code == CDN_TYPECHANGE) 6382 if (hdr_code == CDN_TYPECHANGE)
6355 CommDlg_OpenSave_SetControlText (dialog, 6383 {
6356 FILE_NAME_TEXT_FIELD, 6384 if (use_unicode)
6357 GUISTR ("")); 6385 SendMessageW (dialog, CDM_SETCONTROLTEXT,
6386 FILE_NAME_TEXT_FIELD, (LPARAM)L"");
6387 else
6388 SendMessageA (dialog, CDM_SETCONTROLTEXT,
6389 FILE_NAME_TEXT_FIELD, (LPARAM)"");
6390 }
6358 EnableWindow (edit_control, TRUE); 6391 EnableWindow (edit_control, TRUE);
6359 } 6392 }
6360 } 6393 }
@@ -6374,8 +6407,8 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6374 (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p) 6407 (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p)
6375{ 6408{
6376 /* Filter index: 1: All Files, 2: Directories only */ 6409 /* Filter index: 1: All Files, 2: Directories only */
6377 static const guichar_t filter[] = 6410 static const wchar_t filter_w[] = L"All Files (*.*)\0*.*\0Directories\0*|*\0";
6378 GUISTR ("All Files (*.*)\0*.*\0Directories\0*|*\0"); 6411 static const char filter_a[] = "All Files (*.*)\0*.*\0Directories\0*|*\0";
6379 6412
6380 Lisp_Object filename = default_filename; 6413 Lisp_Object filename = default_filename;
6381 struct frame *f = SELECTED_FRAME (); 6414 struct frame *f = SELECTED_FRAME ();
@@ -6388,25 +6421,36 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6388 enough struct for the new dialog to trick GetOpenFileName into 6421 enough struct for the new dialog to trick GetOpenFileName into
6389 giving us the new dialogs on newer versions of Windows. */ 6422 giving us the new dialogs on newer versions of Windows. */
6390 struct { 6423 struct {
6391#ifdef NTGUI_UNICODE
6392 OPENFILENAMEW details; 6424 OPENFILENAMEW details;
6393#else /* !NTGUI_UNICODE */
6394 OPENFILENAMEA details;
6395#endif /* NTGUI_UNICODE */
6396
6397#if _WIN32_WINNT < 0x500 /* < win2k */ 6425#if _WIN32_WINNT < 0x500 /* < win2k */
6398 PVOID pvReserved; 6426 PVOID pvReserved;
6399 DWORD dwReserved; 6427 DWORD dwReserved;
6400 DWORD FlagsEx; 6428 DWORD FlagsEx;
6401#endif /* < win2k */ 6429#endif /* < win2k */
6402 } new_file_details; 6430 } new_file_details_w;
6403 6431
6404#ifdef NTGUI_UNICODE 6432#ifdef NTGUI_UNICODE
6405 wchar_t filename_buf[32*1024 + 1]; // NT kernel maximum 6433 wchar_t filename_buf_w[32*1024 + 1]; // NT kernel maximum
6406 OPENFILENAMEW * file_details = &new_file_details.details; 6434 OPENFILENAMEW * file_details_w = &new_file_details_w.details;
6435 const int use_unicode = 1;
6407#else /* not NTGUI_UNICODE */ 6436#else /* not NTGUI_UNICODE */
6408 char filename_buf[MAX_PATH + 1]; 6437 struct {
6409 OPENFILENAMEA * file_details = &new_file_details.details; 6438 OPENFILENAMEA details;
6439#if _WIN32_WINNT < 0x500 /* < win2k */
6440 PVOID pvReserved;
6441 DWORD dwReserved;
6442 DWORD FlagsEx;
6443#endif /* < win2k */
6444 } new_file_details_a;
6445 wchar_t filename_buf_w[MAX_PATH + 1], dir_w[MAX_PATH];
6446 char filename_buf_a[MAX_PATH + 1], dir_a[MAX_PATH];
6447 OPENFILENAMEW * file_details_w = &new_file_details_w.details;
6448 OPENFILENAMEA * file_details_a = &new_file_details_a.details;
6449 int use_unicode = w32_unicode_filenames;
6450 wchar_t *prompt_w;
6451 char *prompt_a;
6452 int len;
6453 char fname_ret[MAX_UTF8_PATH];
6410#endif /* NTGUI_UNICODE */ 6454#endif /* NTGUI_UNICODE */
6411 6455
6412 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; 6456 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
@@ -6452,6 +6496,10 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6452 to_unicode (prompt, &prompt); 6496 to_unicode (prompt, &prompt);
6453 to_unicode (dir, &dir); 6497 to_unicode (dir, &dir);
6454 to_unicode (filename, &filename); 6498 to_unicode (filename, &filename);
6499 if (SBYTES (filename) + 1 > sizeof (filename_buf_w))
6500 report_file_error ("filename too long", default_filename);
6501
6502 memcpy (filename_buf_w, SDATA (filename), SBYTES (filename) + 1);
6455#else /* !NTGUI_UNICODE */ 6503#else /* !NTGUI_UNICODE */
6456 prompt = ENCODE_FILE (prompt); 6504 prompt = ENCODE_FILE (prompt);
6457 dir = ENCODE_FILE (dir); 6505 dir = ENCODE_FILE (dir);
@@ -6462,6 +6510,49 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6462 unixtodos_filename (SDATA (dir)); 6510 unixtodos_filename (SDATA (dir));
6463 filename = Fcopy_sequence (filename); 6511 filename = Fcopy_sequence (filename);
6464 unixtodos_filename (SDATA (filename)); 6512 unixtodos_filename (SDATA (filename));
6513 if (SBYTES (filename) >= MAX_UTF8_PATH)
6514 report_file_error ("filename too long", default_filename);
6515 if (w32_unicode_filenames)
6516 {
6517 filename_to_utf16 (SSDATA (dir), dir_w);
6518 if (filename_to_utf16 (SSDATA (filename), filename_buf_w) != 0)
6519 {
6520 /* filename_to_utf16 sets errno to ENOENT when the file
6521 name is too long or cannot be converted to UTF-16. */
6522 if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
6523 report_file_error ("filename too long", default_filename);
6524 }
6525 len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
6526 SSDATA (prompt), -1, NULL, 0);
6527 if (len > 32768)
6528 len = 32768;
6529 prompt_w = alloca (len * sizeof (wchar_t));
6530 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
6531 SSDATA (prompt), -1, prompt_w, len);
6532 }
6533 else
6534 {
6535 filename_to_ansi (SSDATA (dir), dir_a);
6536 if (filename_to_ansi (SSDATA (filename), filename_buf_a) != '\0')
6537 {
6538 /* filename_to_ansi sets errno to ENOENT when the file
6539 name is too long or cannot be converted to UTF-16. */
6540 if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
6541 report_file_error ("filename too long", default_filename);
6542 }
6543 len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
6544 SSDATA (prompt), -1, NULL, 0);
6545 if (len > 32768)
6546 len = 32768;
6547 prompt_w = alloca (len * sizeof (wchar_t));
6548 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
6549 SSDATA (prompt), -1, prompt_w, len);
6550 len = WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL);
6551 if (len > 32768)
6552 len = 32768;
6553 prompt_a = alloca (len);
6554 WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, prompt_a, len, NULL, NULL);
6555 }
6465#endif /* NTGUI_UNICODE */ 6556#endif /* NTGUI_UNICODE */
6466 6557
6467 /* Fill in the structure for the call to GetOpenFileName below. 6558 /* Fill in the structure for the call to GetOpenFileName below.
@@ -6470,48 +6561,88 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6470 builds, we tell the OS we're using an old version of the 6561 builds, we tell the OS we're using an old version of the
6471 structure if the OS isn't new enough to support the newer 6562 structure if the OS isn't new enough to support the newer
6472 version. */ 6563 version. */
6473 memset (&new_file_details, 0, sizeof (new_file_details)); 6564 if (use_unicode)
6474 6565 {
6475 if (w32_major_version > 4 && w32_major_version < 95) 6566 memset (&new_file_details_w, 0, sizeof (new_file_details_w));
6476 file_details->lStructSize = sizeof (new_file_details); 6567 if (w32_major_version > 4 && w32_major_version < 95)
6568 file_details_w->lStructSize = sizeof (new_file_details_w);
6569 else
6570 file_details_w->lStructSize = sizeof (*file_details_w);
6571 /* Set up the inout parameter for the selected file name. */
6572 file_details_w->lpstrFile = filename_buf_w;
6573 file_details_w->nMaxFile =
6574 sizeof (filename_buf_w) / sizeof (*filename_buf_w);
6575 file_details_w->hwndOwner = FRAME_W32_WINDOW (f);
6576 /* Undocumented Bug in Common File Dialog:
6577 If a filter is not specified, shell links are not resolved. */
6578 file_details_w->lpstrFilter = filter_w;
6579#ifdef NTGUI_UNICODE
6580 file_details_w->lpstrInitialDir = (wchar_t*) SDATA (dir);
6581 file_details_w->lpstrTitle = (guichar_t*) SDATA (prompt);
6582#else
6583 file_details_w->lpstrInitialDir = dir_w;
6584 file_details_w->lpstrTitle = prompt_w;
6585#endif
6586 file_details_w->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
6587 file_details_w->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
6588 | OFN_EXPLORER | OFN_ENABLEHOOK);
6589 if (!NILP (mustmatch))
6590 {
6591 /* Require that the path to the parent directory exists. */
6592 file_details_w->Flags |= OFN_PATHMUSTEXIST;
6593 /* If we are looking for a file, require that it exists. */
6594 if (NILP (only_dir_p))
6595 file_details_w->Flags |= OFN_FILEMUSTEXIST;
6596 }
6597 }
6598#ifndef NTGUI_UNICODE
6477 else 6599 else
6478 file_details->lStructSize = sizeof (*file_details);
6479
6480 /* Set up the inout parameter for the selected file name. */
6481 if (SBYTES (filename) + 1 > sizeof (filename_buf))
6482 report_file_error ("filename too long", default_filename);
6483
6484 memcpy (filename_buf, SDATA (filename), SBYTES (filename) + 1);
6485 file_details->lpstrFile = filename_buf;
6486 file_details->nMaxFile = sizeof (filename_buf) / sizeof (*filename_buf);
6487
6488 file_details->hwndOwner = FRAME_W32_WINDOW (f);
6489 /* Undocumented Bug in Common File Dialog:
6490 If a filter is not specified, shell links are not resolved. */
6491 file_details->lpstrFilter = filter;
6492 file_details->lpstrInitialDir = (guichar_t*) SDATA (dir);
6493 file_details->lpstrTitle = (guichar_t*) SDATA (prompt);
6494 file_details->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
6495 file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
6496 | OFN_EXPLORER | OFN_ENABLEHOOK);
6497
6498 if (!NILP (mustmatch))
6499 { 6600 {
6500 /* Require that the path to the parent directory exists. */ 6601 memset (&new_file_details_a, 0, sizeof (new_file_details_a));
6501 file_details->Flags |= OFN_PATHMUSTEXIST; 6602 if (w32_major_version > 4 && w32_major_version < 95)
6502 /* If we are looking for a file, require that it exists. */ 6603 file_details_a->lStructSize = sizeof (new_file_details_a);
6503 if (NILP (only_dir_p)) 6604 else
6504 file_details->Flags |= OFN_FILEMUSTEXIST; 6605 file_details_a->lStructSize = sizeof (*file_details_a);
6606 file_details_a->lpstrFile = filename_buf_a;
6607 file_details_a->nMaxFile =
6608 sizeof (filename_buf_a) / sizeof (*filename_buf_a);
6609 file_details_a->hwndOwner = FRAME_W32_WINDOW (f);
6610 file_details_a->lpstrFilter = filter_a;
6611 file_details_a->lpstrInitialDir = dir_a;
6612 file_details_a->lpstrTitle = prompt_a;
6613 file_details_a->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
6614 file_details_a->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
6615 | OFN_EXPLORER | OFN_ENABLEHOOK);
6616 if (!NILP (mustmatch))
6617 {
6618 /* Require that the path to the parent directory exists. */
6619 file_details_a->Flags |= OFN_PATHMUSTEXIST;
6620 /* If we are looking for a file, require that it exists. */
6621 if (NILP (only_dir_p))
6622 file_details_a->Flags |= OFN_FILEMUSTEXIST;
6623 }
6505 } 6624 }
6625#endif /* !NTGUI_UNICODE */
6506 6626
6507 { 6627 {
6508 int count = SPECPDL_INDEX (); 6628 int count = SPECPDL_INDEX ();
6509 /* Prevent redisplay. */ 6629 /* Prevent redisplay. */
6510 specbind (Qinhibit_redisplay, Qt); 6630 specbind (Qinhibit_redisplay, Qt);
6511 block_input (); 6631 block_input ();
6512 file_details->lpfnHook = file_dialog_callback; 6632 if (use_unicode)
6633 {
6634 file_details_w->lpfnHook = file_dialog_callback;
6635
6636 file_opened = GetOpenFileNameW (file_details_w);
6637 }
6638#ifndef NTGUI_UNICODE
6639 else
6640 {
6641 file_details_a->lpfnHook = file_dialog_callback;
6513 6642
6514 file_opened = GUI_FN (GetOpenFileName) (file_details); 6643 file_opened = GetOpenFileNameA (file_details_a);
6644 }
6645#endif /* !NTGUI_UNICODE */
6515 unblock_input (); 6646 unblock_input ();
6516 unbind_to (count, Qnil); 6647 unbind_to (count, Qnil);
6517 } 6648 }
@@ -6520,10 +6651,14 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6520 { 6651 {
6521 /* Get an Emacs string from the value Windows gave us. */ 6652 /* Get an Emacs string from the value Windows gave us. */
6522#ifdef NTGUI_UNICODE 6653#ifdef NTGUI_UNICODE
6523 filename = from_unicode_buffer (filename_buf); 6654 filename = from_unicode_buffer (filename_buf_w);
6524#else /* !NTGUI_UNICODE */ 6655#else /* !NTGUI_UNICODE */
6525 dostounix_filename (filename_buf, 0); 6656 if (use_unicode)
6526 filename = DECODE_FILE (build_string (filename_buf)); 6657 filename_from_utf16 (filename_buf_w, fname_ret);
6658 else
6659 filename_from_ansi (filename_buf_a, fname_ret);
6660 dostounix_filename (fname_ret);
6661 filename = DECODE_FILE (build_unibyte_string (fname_ret));
6527#endif /* NTGUI_UNICODE */ 6662#endif /* NTGUI_UNICODE */
6528 6663
6529#ifdef CYGWIN 6664#ifdef CYGWIN
@@ -6532,10 +6667,12 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
6532 6667
6533 /* Strip the dummy filename off the end of the string if we 6668 /* Strip the dummy filename off the end of the string if we
6534 added it to select a directory. */ 6669 added it to select a directory. */
6535 if (file_details->nFilterIndex == 2) 6670 if (use_unicode && file_details_w->nFilterIndex == 2
6536 { 6671#ifndef NTGUI_UNICODE
6537 filename = Ffile_name_directory (filename); 6672 || !use_unicode && file_details_a->nFilterIndex == 2
6538 } 6673#endif
6674 )
6675 filename = Ffile_name_directory (filename);
6539 } 6676 }
6540 /* User canceled the dialog without making a selection. */ 6677 /* User canceled the dialog without making a selection. */
6541 else if (!CommDlgExtendedError ()) 6678 else if (!CommDlgExtendedError ())
@@ -6582,38 +6719,80 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
6582 operation = intern ("delete-directory"); 6719 operation = intern ("delete-directory");
6583 filename = Fdirectory_file_name (filename); 6720 filename = Fdirectory_file_name (filename);
6584 } 6721 }
6722
6723 /* Must have fully qualified file names for moving files to Recycle
6724 Bin. */
6585 filename = Fexpand_file_name (filename, Qnil); 6725 filename = Fexpand_file_name (filename, Qnil);
6586 6726
6587 handler = Ffind_file_name_handler (filename, operation); 6727 handler = Ffind_file_name_handler (filename, operation);
6588 if (!NILP (handler)) 6728 if (!NILP (handler))
6589 return call2 (handler, operation, filename); 6729 return call2 (handler, operation, filename);
6730 else
6731 {
6732 const char * path;
6733 int result;
6590 6734
6591 encoded_file = ENCODE_FILE (filename); 6735 encoded_file = ENCODE_FILE (filename);
6592 6736
6593 { 6737 path = map_w32_filename (SDATA (encoded_file), NULL);
6594 const char * path;
6595 SHFILEOPSTRUCT file_op;
6596 char tmp_path[MAX_PATH + 1];
6597 6738
6598 path = map_w32_filename (SDATA (encoded_file), NULL); 6739 /* The Unicode version of SHFileOperation is not supported on
6740 Windows 9X. */
6741 if (w32_unicode_filenames && os_subtype != OS_9X)
6742 {
6743 SHFILEOPSTRUCTW file_op_w;
6744 /* We need one more element beyond MAX_PATH because this is
6745 a list of file names, with the last element double-null
6746 terminated. */
6747 wchar_t tmp_path_w[MAX_PATH + 1];
6748
6749 memset (tmp_path_w, 0, sizeof (tmp_path_w));
6750 filename_to_utf16 (path, tmp_path_w);
6751
6752 /* On Windows, write permission is required to delete/move files. */
6753 _wchmod (tmp_path_w, 0666);
6754
6755 memset (&file_op_w, 0, sizeof (file_op_w));
6756 file_op_w.hwnd = HWND_DESKTOP;
6757 file_op_w.wFunc = FO_DELETE;
6758 file_op_w.pFrom = tmp_path_w;
6759 file_op_w.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
6760 | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
6761 file_op_w.fAnyOperationsAborted = FALSE;
6762
6763 result = SHFileOperationW (&file_op_w);
6764 }
6765 else
6766 {
6767 SHFILEOPSTRUCTA file_op_a;
6768 char tmp_path_a[MAX_PATH + 1];
6599 6769
6600 /* On Windows, write permission is required to delete/move files. */ 6770 memset (tmp_path_a, 0, sizeof (tmp_path_a));
6601 _chmod (path, 0666); 6771 filename_to_ansi (path, tmp_path_a);
6602 6772
6603 memset (tmp_path, 0, sizeof (tmp_path)); 6773 /* If a file cannot be represented in ANSI codepage, don't
6604 strcpy (tmp_path, path); 6774 let them inadvertently delete other files because some
6775 characters are interpreted as a wildcards. */
6776 if (_mbspbrk (tmp_path_a, "?*"))
6777 result = ERROR_FILE_NOT_FOUND;
6778 else
6779 {
6780 _chmod (tmp_path_a, 0666);
6605 6781
6606 memset (&file_op, 0, sizeof (file_op)); 6782 memset (&file_op_a, 0, sizeof (file_op_a));
6607 file_op.hwnd = HWND_DESKTOP; 6783 file_op_a.hwnd = HWND_DESKTOP;
6608 file_op.wFunc = FO_DELETE; 6784 file_op_a.wFunc = FO_DELETE;
6609 file_op.pFrom = tmp_path; 6785 file_op_a.pFrom = tmp_path_a;
6610 file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO 6786 file_op_a.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
6611 | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS; 6787 | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
6612 file_op.fAnyOperationsAborted = FALSE; 6788 file_op_a.fAnyOperationsAborted = FALSE;
6613 6789
6614 if (SHFileOperation (&file_op) != 0) 6790 result = SHFileOperationA (&file_op_a);
6615 report_file_error ("Removing old name", list1 (filename)); 6791 }
6616 } 6792 }
6793 if (result != 0)
6794 report_file_error ("Removing old name", list1 (filename));
6795 }
6617 return Qnil; 6796 return Qnil;
6618} 6797}
6619 6798
@@ -6688,38 +6867,159 @@ an integer representing a ShowWindow flag:
6688 6 - start minimized */) 6867 6 - start minimized */)
6689 (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag) 6868 (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag)
6690{ 6869{
6691 Lisp_Object current_dir;
6692 char *errstr; 6870 char *errstr;
6871 Lisp_Object current_dir = BVAR (current_buffer, directory);;
6872 wchar_t *doc_w = NULL, *params_w = NULL, *ops_w = NULL;
6873 intptr_t result;
6874#ifndef CYGWIN
6875 int use_unicode = w32_unicode_filenames;
6876 char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
6877#endif
6693 6878
6694 CHECK_STRING (document); 6879 CHECK_STRING (document);
6695 6880
6696 /* Encode filename, current directory and parameters. */
6697 current_dir = BVAR (current_buffer, directory);
6698
6699#ifdef CYGWIN 6881#ifdef CYGWIN
6700 current_dir = Fcygwin_convert_file_name_to_windows (current_dir, Qt); 6882 current_dir = Fcygwin_convert_file_name_to_windows (current_dir, Qt);
6701 if (STRINGP (document)) 6883 if (STRINGP (document))
6702 document = Fcygwin_convert_file_name_to_windows (document, Qt); 6884 document = Fcygwin_convert_file_name_to_windows (document, Qt);
6703#endif /* CYGWIN */
6704 6885
6886 /* Encode filename, current directory and parameters. */
6705 current_dir = GUI_ENCODE_FILE (current_dir); 6887 current_dir = GUI_ENCODE_FILE (current_dir);
6706 if (STRINGP (document)) 6888 if (STRINGP (document))
6707 document = GUI_ENCODE_FILE (document); 6889 {
6890 document = GUI_ENCODE_FILE (document);
6891 doc_w = GUI_SDATA (document);
6892 }
6708 if (STRINGP (parameters)) 6893 if (STRINGP (parameters))
6709 parameters = GUI_ENCODE_SYSTEM (parameters); 6894 {
6710 6895 parameters = GUI_ENCODE_SYSTEM (parameters);
6711 if ((int) GUI_FN (ShellExecute) (NULL, 6896 params_w = GUI_SDATA (parameters);
6712 (STRINGP (operation) ? 6897 }
6713 GUI_SDATA (operation) : NULL), 6898 if (STRINGP (operation))
6714 GUI_SDATA (document), 6899 {
6715 (STRINGP (parameters) ? 6900 operation = GUI_ENCODE_SYSTEM (operation);
6716 GUI_SDATA (parameters) : NULL), 6901 ops_w = GUI_SDATA (operation);
6717 GUI_SDATA (current_dir), 6902 }
6718 (INTEGERP (show_flag) ? 6903 result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
6719 XINT (show_flag) : SW_SHOWDEFAULT)) 6904 GUI_SDATA (current_dir),
6720 > 32) 6905 (INTEGERP (show_flag)
6906 ? XINT (show_flag) : SW_SHOWDEFAULT));
6907#else /* !CYGWIN */
6908 if (use_unicode)
6909 {
6910 wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
6911
6912 /* Encode filename, current directory and parameters, and
6913 convert operation to UTF-16. */
6914 current_dir = ENCODE_FILE (current_dir);
6915 filename_to_utf16 (SSDATA (current_dir), current_dir_w);
6916 if (STRINGP (document))
6917 {
6918 document = ENCODE_FILE (document);
6919 filename_to_utf16 (SSDATA (document), document_w);
6920 doc_w = document_w;
6921 }
6922 if (STRINGP (parameters))
6923 {
6924 int len;
6925
6926 parameters = ENCODE_SYSTEM (parameters);
6927 len = MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
6928 SSDATA (parameters), -1, NULL, 0);
6929 if (len > 32768)
6930 len = 32768;
6931 params_w = alloca (len * sizeof (wchar_t));
6932 MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
6933 SSDATA (parameters), -1, params_w, len);
6934 }
6935 if (STRINGP (operation))
6936 {
6937 /* Assume OPERATION is pure ASCII. */
6938 const char *s = SSDATA (operation);
6939 wchar_t *d;
6940 int len = SBYTES (operation) + 1;
6941
6942 if (len > 32768)
6943 len = 32768;
6944 d = ops_w = alloca (len * sizeof (wchar_t));
6945 while (d < ops_w + len - 1)
6946 *d++ = *s++;
6947 *d = 0;
6948 }
6949 result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
6950 current_dir_w,
6951 (INTEGERP (show_flag)
6952 ? XINT (show_flag) : SW_SHOWDEFAULT));
6953 }
6954 else
6955 {
6956 char document_a[MAX_PATH], current_dir_a[MAX_PATH];
6957
6958 current_dir = ENCODE_FILE (current_dir);
6959 filename_to_ansi (SSDATA (current_dir), current_dir_a);
6960 if (STRINGP (document))
6961 {
6962 ENCODE_FILE (document);
6963 filename_to_ansi (SSDATA (document), document_a);
6964 doc_a = document_a;
6965 }
6966 if (STRINGP (parameters))
6967 {
6968 int len;
6969
6970 parameters = ENCODE_SYSTEM (parameters);
6971 params_a = SSDATA (parameters);
6972 }
6973 if (STRINGP (operation))
6974 {
6975 /* Assume OPERATION is pure ASCII. */
6976 ops_a = SSDATA (operation);
6977 }
6978 result = (intptr_t) ShellExecuteA (NULL, ops_a, doc_a, params_a,
6979 current_dir_a,
6980 (INTEGERP (show_flag)
6981 ? XINT (show_flag) : SW_SHOWDEFAULT));
6982 }
6983#endif /* !CYGWIN */
6984
6985 if (result > 32)
6721 return Qt; 6986 return Qt;
6722 errstr = w32_strerror (0); 6987
6988 switch (result)
6989 {
6990 case SE_ERR_ACCESSDENIED:
6991 errstr = w32_strerror (ERROR_ACCESS_DENIED);
6992 break;
6993 case SE_ERR_ASSOCINCOMPLETE:
6994 case SE_ERR_NOASSOC:
6995 errstr = w32_strerror (ERROR_NO_ASSOCIATION);
6996 break;
6997 case SE_ERR_DDEBUSY:
6998 case SE_ERR_DDEFAIL:
6999 errstr = w32_strerror (ERROR_DDE_FAIL);
7000 break;
7001 case SE_ERR_DDETIMEOUT:
7002 errstr = w32_strerror (ERROR_TIMEOUT);
7003 break;
7004 case SE_ERR_DLLNOTFOUND:
7005 errstr = w32_strerror (ERROR_DLL_NOT_FOUND);
7006 break;
7007 case SE_ERR_FNF:
7008 errstr = w32_strerror (ERROR_FILE_NOT_FOUND);
7009 break;
7010 case SE_ERR_OOM:
7011 errstr = w32_strerror (ERROR_NOT_ENOUGH_MEMORY);
7012 break;
7013 case SE_ERR_PNF:
7014 errstr = w32_strerror (ERROR_PATH_NOT_FOUND);
7015 break;
7016 case SE_ERR_SHARE:
7017 errstr = w32_strerror (ERROR_SHARING_VIOLATION);
7018 break;
7019 default:
7020 errstr = w32_strerror (0);
7021 break;
7022 }
6723 /* The error string might be encoded in the locale's encoding. */ 7023 /* The error string might be encoded in the locale's encoding. */
6724 if (!NILP (Vlocale_coding_system)) 7024 if (!NILP (Vlocale_coding_system))
6725 { 7025 {
@@ -7132,14 +7432,23 @@ If the underlying system call fails, value is nil. */)
7132 added rather late on. */ 7432 added rather late on. */
7133 { 7433 {
7134 HMODULE hKernel = GetModuleHandle ("kernel32"); 7434 HMODULE hKernel = GetModuleHandle ("kernel32");
7135 BOOL (*pfn_GetDiskFreeSpaceEx) 7435 BOOL (*pfn_GetDiskFreeSpaceExW)
7436 (wchar_t *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
7437 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExW");
7438 BOOL (*pfn_GetDiskFreeSpaceExA)
7136 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) 7439 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
7137 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx"); 7440 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExA");
7441 bool have_pfn_GetDiskFreeSpaceEx =
7442 (w32_unicode_filenames && pfn_GetDiskFreeSpaceExW
7443 || !w32_unicode_filenames && pfn_GetDiskFreeSpaceExA);
7138 7444
7139 /* On Windows, we may need to specify the root directory of the 7445 /* On Windows, we may need to specify the root directory of the
7140 volume holding FILENAME. */ 7446 volume holding FILENAME. */
7141 char rootname[MAX_PATH]; 7447 char rootname[MAX_UTF8_PATH];
7448 wchar_t rootname_w[MAX_PATH];
7449 char rootname_a[MAX_PATH];
7142 char *name = SDATA (encoded); 7450 char *name = SDATA (encoded);
7451 BOOL result;
7143 7452
7144 /* find the root name of the volume if given */ 7453 /* find the root name of the volume if given */
7145 if (isalpha (name[0]) && name[1] == ':') 7454 if (isalpha (name[0]) && name[1] == ':')
@@ -7165,7 +7474,12 @@ If the underlying system call fails, value is nil. */)
7165 *str = 0; 7474 *str = 0;
7166 } 7475 }
7167 7476
7168 if (pfn_GetDiskFreeSpaceEx) 7477 if (w32_unicode_filenames)
7478 filename_to_utf16 (rootname, rootname_w);
7479 else
7480 filename_to_ansi (rootname, rootname_a);
7481
7482 if (have_pfn_GetDiskFreeSpaceEx)
7169 { 7483 {
7170 /* Unsigned large integers cannot be cast to double, so 7484 /* Unsigned large integers cannot be cast to double, so
7171 use signed ones instead. */ 7485 use signed ones instead. */
@@ -7173,10 +7487,17 @@ If the underlying system call fails, value is nil. */)
7173 LARGE_INTEGER freebytes; 7487 LARGE_INTEGER freebytes;
7174 LARGE_INTEGER totalbytes; 7488 LARGE_INTEGER totalbytes;
7175 7489
7176 if (pfn_GetDiskFreeSpaceEx (rootname, 7490 if (w32_unicode_filenames)
7177 (ULARGE_INTEGER *)&availbytes, 7491 result = pfn_GetDiskFreeSpaceExW (rootname_w,
7178 (ULARGE_INTEGER *)&totalbytes, 7492 (ULARGE_INTEGER *)&availbytes,
7179 (ULARGE_INTEGER *)&freebytes)) 7493 (ULARGE_INTEGER *)&totalbytes,
7494 (ULARGE_INTEGER *)&freebytes);
7495 else
7496 result = pfn_GetDiskFreeSpaceExA (rootname_a,
7497 (ULARGE_INTEGER *)&availbytes,
7498 (ULARGE_INTEGER *)&totalbytes,
7499 (ULARGE_INTEGER *)&freebytes);
7500 if (result)
7180 value = list3 (make_float ((double) totalbytes.QuadPart), 7501 value = list3 (make_float ((double) totalbytes.QuadPart),
7181 make_float ((double) freebytes.QuadPart), 7502 make_float ((double) freebytes.QuadPart),
7182 make_float ((double) availbytes.QuadPart)); 7503 make_float ((double) availbytes.QuadPart));
@@ -7188,11 +7509,19 @@ If the underlying system call fails, value is nil. */)
7188 DWORD free_clusters; 7509 DWORD free_clusters;
7189 DWORD total_clusters; 7510 DWORD total_clusters;
7190 7511
7191 if (GetDiskFreeSpace (rootname, 7512 if (w32_unicode_filenames)
7192 &sectors_per_cluster, 7513 result = GetDiskFreeSpaceW (rootname_w,
7193 &bytes_per_sector, 7514 &sectors_per_cluster,
7194 &free_clusters, 7515 &bytes_per_sector,
7195 &total_clusters)) 7516 &free_clusters,
7517 &total_clusters);
7518 else
7519 result = GetDiskFreeSpaceA (rootname_a,
7520 &sectors_per_cluster,
7521 &bytes_per_sector,
7522 &free_clusters,
7523 &total_clusters);
7524 if (result)
7196 value = list3 (make_float ((double) total_clusters 7525 value = list3 (make_float ((double) total_clusters
7197 * sectors_per_cluster * bytes_per_sector), 7526 * sectors_per_cluster * bytes_per_sector),
7198 make_float ((double) free_clusters 7527 make_float ((double) free_clusters
@@ -7207,6 +7536,7 @@ If the underlying system call fails, value is nil. */)
7207#endif /* WINDOWSNT */ 7536#endif /* WINDOWSNT */
7208 7537
7209 7538
7539#ifdef WINDOWSNT
7210DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name, 7540DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
7211 0, 0, 0, doc: /* Return the name of Windows default printer device. */) 7541 0, 0, 0, doc: /* Return the name of Windows default printer device. */)
7212 (void) 7542 (void)
@@ -7214,8 +7544,11 @@ DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
7214 static char pname_buf[256]; 7544 static char pname_buf[256];
7215 int err; 7545 int err;
7216 HANDLE hPrn; 7546 HANDLE hPrn;
7217 PRINTER_INFO_2 *ppi2 = NULL; 7547 PRINTER_INFO_2W *ppi2w = NULL;
7548 PRINTER_INFO_2A *ppi2a = NULL;
7218 DWORD dwNeeded = 0, dwReturned = 0; 7549 DWORD dwNeeded = 0, dwReturned = 0;
7550 char server_name[MAX_UTF8_PATH], share_name[MAX_UTF8_PATH];
7551 char port_name[MAX_UTF8_PATH];
7219 7552
7220 /* Retrieve the default string from Win.ini (the registry). 7553 /* Retrieve the default string from Win.ini (the registry).
7221 * String will be in form "printername,drivername,portname". 7554 * String will be in form "printername,drivername,portname".
@@ -7227,55 +7560,89 @@ DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
7227 /* We want to know more than the printer name */ 7560 /* We want to know more than the printer name */
7228 if (!OpenPrinter (pname_buf, &hPrn, NULL)) 7561 if (!OpenPrinter (pname_buf, &hPrn, NULL))
7229 return Qnil; 7562 return Qnil;
7230 GetPrinter (hPrn, 2, NULL, 0, &dwNeeded); 7563 /* GetPrinterW is not supported by unicows.dll. */
7564 if (w32_unicode_filenames && os_subtype != OS_9X)
7565 GetPrinterW (hPrn, 2, NULL, 0, &dwNeeded);
7566 else
7567 GetPrinterA (hPrn, 2, NULL, 0, &dwNeeded);
7231 if (dwNeeded == 0) 7568 if (dwNeeded == 0)
7232 { 7569 {
7233 ClosePrinter (hPrn); 7570 ClosePrinter (hPrn);
7234 return Qnil; 7571 return Qnil;
7235 } 7572 }
7236 /* Allocate memory for the PRINTER_INFO_2 struct */ 7573 /* Call GetPrinter again with big enough memory block. */
7237 ppi2 = xmalloc (dwNeeded); 7574 if (w32_unicode_filenames && os_subtype != OS_9X)
7238 if (!ppi2)
7239 { 7575 {
7576 /* Allocate memory for the PRINTER_INFO_2 struct. */
7577 ppi2w = xmalloc (dwNeeded);
7578 err = GetPrinterW (hPrn, 2, (LPBYTE)ppi2w, dwNeeded, &dwReturned);
7240 ClosePrinter (hPrn); 7579 ClosePrinter (hPrn);
7241 return Qnil; 7580 if (!err)
7581 {
7582 xfree (ppi2w);
7583 return Qnil;
7584 }
7585
7586 if ((ppi2w->Attributes & PRINTER_ATTRIBUTE_SHARED)
7587 && ppi2w->pServerName)
7588 {
7589 filename_from_utf16 (ppi2w->pServerName, server_name);
7590 filename_from_utf16 (ppi2w->pShareName, share_name);
7591 }
7592 else
7593 {
7594 server_name[0] = '\0';
7595 filename_from_utf16 (ppi2w->pPortName, port_name);
7596 }
7242 } 7597 }
7243 /* Call GetPrinter again with big enough memory block. */ 7598 else
7244 err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
7245 ClosePrinter (hPrn);
7246 if (!err)
7247 { 7599 {
7248 xfree (ppi2); 7600 ppi2a = xmalloc (dwNeeded);
7249 return Qnil; 7601 err = GetPrinterA (hPrn, 2, (LPBYTE)ppi2a, dwNeeded, &dwReturned);
7250 } 7602 ClosePrinter (hPrn);
7603 if (!err)
7604 {
7605 xfree (ppi2a);
7606 return Qnil;
7607 }
7251 7608
7252 if (ppi2) 7609 if ((ppi2a->Attributes & PRINTER_ATTRIBUTE_SHARED)
7253 { 7610 && ppi2a->pServerName)
7254 if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName) 7611 {
7255 { 7612 filename_from_ansi (ppi2a->pServerName, server_name);
7256 /* a remote printer */ 7613 filename_from_ansi (ppi2a->pShareName, share_name);
7257 if (*ppi2->pServerName == '\\')
7258 snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
7259 ppi2->pShareName);
7260 else
7261 snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
7262 ppi2->pShareName);
7263 pname_buf[sizeof (pname_buf) - 1] = '\0';
7264 } 7614 }
7265 else 7615 else
7266 { 7616 {
7267 /* a local printer */ 7617 server_name[0] = '\0';
7268 strncpy (pname_buf, ppi2->pPortName, sizeof (pname_buf)); 7618 filename_from_ansi (ppi2a->pPortName, port_name);
7269 pname_buf[sizeof (pname_buf) - 1] = '\0';
7270 /* `pPortName' can include several ports, delimited by ','.
7271 * we only use the first one. */
7272 strtok (pname_buf, ",");
7273 } 7619 }
7274 xfree (ppi2);
7275 } 7620 }
7276 7621
7277 return build_string (pname_buf); 7622 if (server_name[0])
7623 {
7624 /* a remote printer */
7625 if (server_name[0] == '\\')
7626 snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", server_name,
7627 share_name);
7628 else
7629 snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", server_name,
7630 share_name);
7631 pname_buf[sizeof (pname_buf) - 1] = '\0';
7632 }
7633 else
7634 {
7635 /* a local printer */
7636 strncpy (pname_buf, port_name, sizeof (pname_buf));
7637 pname_buf[sizeof (pname_buf) - 1] = '\0';
7638 /* `pPortName' can include several ports, delimited by ','.
7639 * we only use the first one. */
7640 strtok (pname_buf, ",");
7641 }
7642
7643 return DECODE_FILE (build_unibyte_string (pname_buf));
7278} 7644}
7645#endif /* WINDOWSNT */
7279 7646
7280 7647
7281/* Equivalent of strerror for W32 error codes. */ 7648/* Equivalent of strerror for W32 error codes. */
@@ -7946,9 +8313,9 @@ only be necessary if the default setting causes problems. */);
7946 8313
7947#ifdef WINDOWSNT 8314#ifdef WINDOWSNT
7948 defsubr (&Sfile_system_info); 8315 defsubr (&Sfile_system_info);
8316 defsubr (&Sdefault_printer_name);
7949#endif 8317#endif
7950 8318
7951 defsubr (&Sdefault_printer_name);
7952 defsubr (&Sset_message_beep); 8319 defsubr (&Sset_message_beep);
7953 8320
7954 hourglass_hwnd = NULL; 8321 hourglass_hwnd = NULL;
diff --git a/src/w32notify.c b/src/w32notify.c
index 373e20e8e92..da7c5513dc3 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -105,7 +105,7 @@ struct notification {
105 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */ 105 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
106 BOOL subtree; /* whether to watch subdirectories */ 106 BOOL subtree; /* whether to watch subdirectories */
107 DWORD filter; /* bit mask for events to watch */ 107 DWORD filter; /* bit mask for events to watch */
108 char *watchee; /* the file we are interested in */ 108 char *watchee; /* the file we are interested in, UTF-8 encoded */
109 HANDLE dir; /* handle to the watched directory */ 109 HANDLE dir; /* handle to the watched directory */
110 HANDLE thr; /* handle to the thread that watches */ 110 HANDLE thr; /* handle to the thread that watches */
111 volatile int terminate; /* if non-zero, request for the thread to terminate */ 111 volatile int terminate; /* if non-zero, request for the thread to terminate */
@@ -332,15 +332,43 @@ add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
332 if (!file) 332 if (!file)
333 return NULL; 333 return NULL;
334 334
335 hdir = CreateFile (parent_dir, 335 if (w32_unicode_filenames)
336 FILE_LIST_DIRECTORY, 336 {
337 /* FILE_SHARE_DELETE doesn't preclude other 337 wchar_t dir_w[MAX_PATH], file_w[MAX_PATH];
338 processes from deleting files inside 338
339 parent_dir. */ 339 filename_to_utf16 (parent_dir, dir_w);
340 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 340 if (*file)
341 NULL, OPEN_EXISTING, 341 filename_to_utf16 (file, file_w);
342 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 342 else
343 NULL); 343 file_w[0] = 0;
344
345 hdir = CreateFileW (dir_w,
346 FILE_LIST_DIRECTORY,
347 /* FILE_SHARE_DELETE doesn't preclude other
348 processes from deleting files inside
349 parent_dir. */
350 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
351 NULL, OPEN_EXISTING,
352 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
353 NULL);
354 }
355 else
356 {
357 char dir_a[MAX_PATH], file_a[MAX_PATH];
358
359 filename_to_ansi (parent_dir, dir_a);
360 if (*file)
361 filename_to_ansi (file, file_a);
362 else
363 file_a[0] = '\0';
364
365 hdir = CreateFileA (dir_a,
366 FILE_LIST_DIRECTORY,
367 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
368 NULL, OPEN_EXISTING,
369 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
370 NULL);
371 }
344 if (hdir == INVALID_HANDLE_VALUE) 372 if (hdir == INVALID_HANDLE_VALUE)
345 return NULL; 373 return NULL;
346 374
@@ -490,9 +518,7 @@ will never come in. Volumes shared from remote Windows machines do
490generate notifications correctly, though. */) 518generate notifications correctly, though. */)
491 (Lisp_Object file, Lisp_Object filter, Lisp_Object callback) 519 (Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
492{ 520{
493 Lisp_Object encoded_file, watch_object, watch_descriptor; 521 Lisp_Object dirfn, basefn, watch_object, watch_descriptor;
494 char parent_dir[MAX_PATH], *basename;
495 size_t fn_len;
496 DWORD flags; 522 DWORD flags;
497 BOOL subdirs = FALSE; 523 BOOL subdirs = FALSE;
498 struct notification *dirwatch = NULL; 524 struct notification *dirwatch = NULL;
@@ -510,49 +536,33 @@ generate notifications correctly, though. */)
510 Qnil); 536 Qnil);
511 } 537 }
512 538
513 /* We need a full absolute file name of FILE, and we need to remove
514 any trailing slashes from it, so that GetFullPathName below gets
515 the basename part correctly. */
516 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
517 encoded_file = ENCODE_FILE (file);
518
519 fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir,
520 &basename);
521 if (!fn_len)
522 {
523 errstr = w32_strerror (0);
524 errno = EINVAL;
525 if (!NILP (Vlocale_coding_system))
526 lisp_errstr
527 = code_convert_string_norecord (build_unibyte_string (errstr),
528 Vlocale_coding_system, 0);
529 else
530 lisp_errstr = build_string (errstr);
531 report_file_error ("GetFullPathName failed",
532 Fcons (lisp_errstr, Fcons (file, Qnil)));
533 }
534 /* filenotify.el always passes us a directory, either the parent 539 /* filenotify.el always passes us a directory, either the parent
535 directory of a file to be watched, or the directory to be 540 directory of a file to be watched, or the directory to be
536 watched. */ 541 watched. */
537 if (file_directory_p (parent_dir)) 542 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
538 basename = ""; 543 if (NILP (Ffile_directory_p (file)))
539 else
540 { 544 {
541 /* This should only happen if we are called directly, not via 545 /* This should only happen if we are called directly, not via
542 filenotify.el. If BASENAME is NULL, the argument was the 546 filenotify.el. If BASEFN is empty, the argument was the root
543 root directory on its drive. */ 547 directory on its drive. */
544 if (basename) 548 dirfn = ENCODE_FILE (Ffile_name_directory (file));
545 basename[-1] = '\0'; 549 basefn = ENCODE_FILE (Ffile_name_nondirectory (file));
546 else 550 if (*SDATA (basefn) == '\0')
547 subdirs = TRUE; 551 subdirs = TRUE;
548 } 552 }
553 else
554 {
555 dirfn = ENCODE_FILE (file);
556 basefn = Qnil;
557 }
549 558
550 if (!NILP (Fmember (Qsubtree, filter))) 559 if (!NILP (Fmember (Qsubtree, filter)))
551 subdirs = TRUE; 560 subdirs = TRUE;
552 561
553 flags = filter_list_to_flags (filter); 562 flags = filter_list_to_flags (filter);
554 563
555 dirwatch = add_watch (parent_dir, basename, subdirs, flags); 564 dirwatch = add_watch (SSDATA (dirfn), NILP (basefn) ? "" : SSDATA (basefn),
565 subdirs, flags);
556 if (!dirwatch) 566 if (!dirwatch)
557 { 567 {
558 DWORD err = GetLastError (); 568 DWORD err = GetLastError ();
diff --git a/src/w32proc.c b/src/w32proc.c
index 3e0081cd802..7d4fb9825fa 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30#include <fcntl.h> 30#include <fcntl.h>
31#include <signal.h> 31#include <signal.h>
32#include <sys/file.h> 32#include <sys/file.h>
33#include <mbstring.h>
33 34
34/* must include CRT headers *before* config.h */ 35/* must include CRT headers *before* config.h */
35#include <config.h> 36#include <config.h>
@@ -861,8 +862,6 @@ new_child (void)
861 cp->pid = -1; 862 cp->pid = -1;
862 cp->procinfo.hProcess = NULL; 863 cp->procinfo.hProcess = NULL;
863 cp->status = STATUS_READ_ERROR; 864 cp->status = STATUS_READ_ERROR;
864 cp->input_file = NULL;
865 cp->pending_deletion = 0;
866 865
867 /* use manual reset event so that select() will function properly */ 866 /* use manual reset event so that select() will function properly */
868 cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL); 867 cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
@@ -911,21 +910,6 @@ delete_child (child_process *cp)
911 if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL) 910 if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
912 return; 911 return;
913 912
914 /* Delete the child's temporary input file, if any, that is pending
915 deletion. */
916 if (cp->input_file)
917 {
918 if (cp->pending_deletion)
919 {
920 if (unlink (cp->input_file))
921 DebPrint (("delete_child.unlink (%s) failed, errno: %d\n",
922 cp->input_file, errno));
923 cp->pending_deletion = 0;
924 }
925 xfree (cp->input_file);
926 cp->input_file = NULL;
927 }
928
929 /* reap thread if necessary */ 913 /* reap thread if necessary */
930 if (cp->thrd) 914 if (cp->thrd)
931 { 915 {
@@ -1073,9 +1057,10 @@ reader_thread (void *arg)
1073 return 0; 1057 return 0;
1074} 1058}
1075 1059
1076/* To avoid Emacs changing directory, we just record here the directory 1060/* To avoid Emacs changing directory, we just record here the
1077 the new process should start in. This is set just before calling 1061 directory the new process should start in. This is set just before
1078 sys_spawnve, and is not generally valid at any other time. */ 1062 calling sys_spawnve, and is not generally valid at any other time.
1063 Note that this directory's name is UTF-8 encoded. */
1079static char * process_dir; 1064static char * process_dir;
1080 1065
1081static BOOL 1066static BOOL
@@ -1088,7 +1073,8 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
1088 SECURITY_DESCRIPTOR sec_desc; 1073 SECURITY_DESCRIPTOR sec_desc;
1089#endif 1074#endif
1090 DWORD flags; 1075 DWORD flags;
1091 char dir[ MAXPATHLEN ]; 1076 char dir[ MAX_PATH ];
1077 char *p;
1092 1078
1093 if (cp == NULL) emacs_abort (); 1079 if (cp == NULL) emacs_abort ();
1094 1080
@@ -1118,16 +1104,22 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
1118 sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */; 1104 sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
1119 sec_attrs.bInheritHandle = FALSE; 1105 sec_attrs.bInheritHandle = FALSE;
1120 1106
1121 strcpy (dir, process_dir); 1107 filename_to_ansi (process_dir, dir);
1122 unixtodos_filename (dir); 1108 /* Can't use unixtodos_filename here, since that needs its file name
1109 argument encoded in UTF-8. OTOH, process_dir, which _is_ in
1110 UTF-8, points, to the directory computed by our caller, and we
1111 don't want to modify that, either. */
1112 for (p = dir; *p; p = CharNextA (p))
1113 if (*p == '/')
1114 *p = '\\';
1123 1115
1124 flags = (!NILP (Vw32_start_process_share_console) 1116 flags = (!NILP (Vw32_start_process_share_console)
1125 ? CREATE_NEW_PROCESS_GROUP 1117 ? CREATE_NEW_PROCESS_GROUP
1126 : CREATE_NEW_CONSOLE); 1118 : CREATE_NEW_CONSOLE);
1127 if (NILP (Vw32_start_process_inherit_error_mode)) 1119 if (NILP (Vw32_start_process_inherit_error_mode))
1128 flags |= CREATE_DEFAULT_ERROR_MODE; 1120 flags |= CREATE_DEFAULT_ERROR_MODE;
1129 if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE, 1121 if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
1130 flags, env, dir, &start, &cp->procinfo)) 1122 flags, env, dir, &start, &cp->procinfo))
1131 goto EH_Fail; 1123 goto EH_Fail;
1132 1124
1133 cp->pid = (int) cp->procinfo.dwProcessId; 1125 cp->pid = (int) cp->procinfo.dwProcessId;
@@ -1182,45 +1174,6 @@ register_child (pid_t pid, int fd)
1182 fd_info[fd].cp = cp; 1174 fd_info[fd].cp = cp;
1183} 1175}
1184 1176
1185/* Record INFILE as an input file for process PID. */
1186void
1187record_infile (pid_t pid, char *infile)
1188{
1189 child_process *cp;
1190
1191 /* INFILE should never be NULL, since xstrdup would have signaled
1192 memory full condition in that case, see callproc.c where this
1193 function is called. */
1194 eassert (infile);
1195
1196 cp = find_child_pid ((DWORD)pid);
1197 if (cp == NULL)
1198 {
1199 DebPrint (("record_infile is unable to find pid %lu\n", pid));
1200 return;
1201 }
1202
1203 cp->input_file = infile;
1204}
1205
1206/* Mark the input file INFILE of the corresponding subprocess as
1207 temporary, to be deleted when the subprocess exits. */
1208void
1209record_pending_deletion (char *infile)
1210{
1211 child_process *cp;
1212
1213 eassert (infile);
1214
1215 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1216 if (CHILD_ACTIVE (cp)
1217 && cp->input_file && xstrcasecmp (cp->input_file, infile) == 0)
1218 {
1219 cp->pending_deletion = 1;
1220 break;
1221 }
1222}
1223
1224/* Called from waitpid when a process exits. */ 1177/* Called from waitpid when a process exits. */
1225static void 1178static void
1226reap_subprocess (child_process *cp) 1179reap_subprocess (child_process *cp)
@@ -1427,6 +1380,8 @@ waitpid (pid_t pid, int *status, int options)
1427# define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER 1380# define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
1428#endif 1381#endif
1429 1382
1383/* Implementation note: This function works with file names encoded in
1384 the current ANSI codepage. */
1430static void 1385static void
1431w32_executable_type (char * filename, 1386w32_executable_type (char * filename,
1432 int * is_dos_app, 1387 int * is_dos_app,
@@ -1617,6 +1572,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1617 char *sepchars = " \t*?"; 1572 char *sepchars = " \t*?";
1618 /* This is for native w32 apps; modified below for Cygwin apps. */ 1573 /* This is for native w32 apps; modified below for Cygwin apps. */
1619 char escape_char = '\\'; 1574 char escape_char = '\\';
1575 char cmdname_a[MAX_PATH];
1620 1576
1621 /* We don't care about the other modes */ 1577 /* We don't care about the other modes */
1622 if (mode != _P_NOWAIT) 1578 if (mode != _P_NOWAIT)
@@ -1625,12 +1581,15 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1625 return -1; 1581 return -1;
1626 } 1582 }
1627 1583
1628 /* Handle executable names without an executable suffix. */ 1584 /* Handle executable names without an executable suffix. The caller
1629 program = build_string (cmdname); 1585 already searched exec-path and verified the file is executable,
1630 if (NILP (Ffile_executable_p (program))) 1586 but start-process doesn't do that for file names that are already
1587 absolute. So we double-check this here, just in case. */
1588 if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0)
1631 { 1589 {
1632 struct gcpro gcpro1; 1590 struct gcpro gcpro1;
1633 1591
1592 program = build_string (cmdname);
1634 full = Qnil; 1593 full = Qnil;
1635 GCPRO1 (program); 1594 GCPRO1 (program);
1636 openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK)); 1595 openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK));
@@ -1640,12 +1599,27 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1640 errno = EINVAL; 1599 errno = EINVAL;
1641 return -1; 1600 return -1;
1642 } 1601 }
1643 program = full; 1602 program = ENCODE_FILE (full);
1603 cmdname = SDATA (program);
1644 } 1604 }
1645 1605
1646 /* make sure argv[0] and cmdname are both in DOS format */ 1606 /* make sure argv[0] and cmdname are both in DOS format */
1647 cmdname = SDATA (program);
1648 unixtodos_filename (cmdname); 1607 unixtodos_filename (cmdname);
1608 /* argv[0] was encoded by caller using ENCODE_FILE, so it is in
1609 UTF-8. All the other arguments are encoded by ENCODE_SYSTEM or
1610 some such, and are in some ANSI codepage. We need to have
1611 argv[0] encoded in ANSI codepage. */
1612 filename_to_ansi (cmdname, cmdname_a);
1613 /* We explicitly require that the command's file name be encodable
1614 in the current ANSI codepage, because we will be invoking it via
1615 the ANSI APIs. */
1616 if (_mbspbrk (cmdname_a, "?"))
1617 {
1618 errno = ENOENT;
1619 return -1;
1620 }
1621 /* From here on, CMDNAME is an ANSI-encoded string. */
1622 cmdname = cmdname_a;
1649 argv[0] = cmdname; 1623 argv[0] = cmdname;
1650 1624
1651 /* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows 1625 /* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
@@ -1663,7 +1637,9 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1663 while leaving the real app name as argv[0]. */ 1637 while leaving the real app name as argv[0]. */
1664 if (is_dos_app) 1638 if (is_dos_app)
1665 { 1639 {
1666 cmdname = alloca (MAXPATHLEN); 1640 char *p;
1641
1642 cmdname = alloca (MAX_PATH);
1667 if (egetenv ("CMDPROXY")) 1643 if (egetenv ("CMDPROXY"))
1668 strcpy (cmdname, egetenv ("CMDPROXY")); 1644 strcpy (cmdname, egetenv ("CMDPROXY"));
1669 else 1645 else
@@ -1671,7 +1647,12 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1671 strcpy (cmdname, SDATA (Vinvocation_directory)); 1647 strcpy (cmdname, SDATA (Vinvocation_directory));
1672 strcat (cmdname, "cmdproxy.exe"); 1648 strcat (cmdname, "cmdproxy.exe");
1673 } 1649 }
1674 unixtodos_filename (cmdname); 1650
1651 /* Can't use unixtodos_filename here, since that needs its file
1652 name argument encoded in UTF-8. */
1653 for (p = cmdname; *p; p = CharNextA (p))
1654 if (*p == '/')
1655 *p = '\\';
1675 } 1656 }
1676 1657
1677 /* we have to do some conjuring here to put argv and envp into the 1658 /* we have to do some conjuring here to put argv and envp into the
@@ -2673,10 +2654,11 @@ All path elements in FILENAME are converted to their short names. */)
2673 filename = Fexpand_file_name (filename, Qnil); 2654 filename = Fexpand_file_name (filename, Qnil);
2674 2655
2675 /* luckily, this returns the short version of each element in the path. */ 2656 /* luckily, this returns the short version of each element in the path. */
2676 if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0) 2657 if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)),
2658 shortname, MAX_PATH) == 0)
2677 return Qnil; 2659 return Qnil;
2678 2660
2679 dostounix_filename (shortname, 0); 2661 dostounix_filename (shortname);
2680 2662
2681 /* No need to DECODE_FILE, because 8.3 names are pure ASCII. */ 2663 /* No need to DECODE_FILE, because 8.3 names are pure ASCII. */
2682 return build_string (shortname); 2664 return build_string (shortname);
@@ -2690,7 +2672,7 @@ If FILENAME does not exist, return nil.
2690All path elements in FILENAME are converted to their long names. */) 2672All path elements in FILENAME are converted to their long names. */)
2691 (Lisp_Object filename) 2673 (Lisp_Object filename)
2692{ 2674{
2693 char longname[ MAX_PATH ]; 2675 char longname[ MAX_UTF8_PATH ];
2694 int drive_only = 0; 2676 int drive_only = 0;
2695 2677
2696 CHECK_STRING (filename); 2678 CHECK_STRING (filename);
@@ -2702,10 +2684,11 @@ All path elements in FILENAME are converted to their long names. */)
2702 /* first expand it. */ 2684 /* first expand it. */
2703 filename = Fexpand_file_name (filename, Qnil); 2685 filename = Fexpand_file_name (filename, Qnil);
2704 2686
2705 if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH)) 2687 if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname,
2688 MAX_UTF8_PATH))
2706 return Qnil; 2689 return Qnil;
2707 2690
2708 dostounix_filename (longname, 0); 2691 dostounix_filename (longname);
2709 2692
2710 /* If we were passed only a drive, make sure that a slash is not appended 2693 /* If we were passed only a drive, make sure that a slash is not appended
2711 for consistency with directories. Allow for drive mapping via SUBST 2694 for consistency with directories. Allow for drive mapping via SUBST
@@ -2713,7 +2696,7 @@ All path elements in FILENAME are converted to their long names. */)
2713 if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3]) 2696 if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
2714 longname[2] = '\0'; 2697 longname[2] = '\0';
2715 2698
2716 return DECODE_FILE (build_string (longname)); 2699 return DECODE_FILE (build_unibyte_string (longname));
2717} 2700}
2718 2701
2719DEFUN ("w32-set-process-priority", Fw32_set_process_priority, 2702DEFUN ("w32-set-process-priority", Fw32_set_process_priority,
diff --git a/src/w32term.c b/src/w32term.c
index ec11bc11535..3d6b653157b 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -52,6 +52,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
52#include "keymap.h" 52#include "keymap.h"
53 53
54#ifdef WINDOWSNT 54#ifdef WINDOWSNT
55#include "w32.h" /* for filename_from_utf16, filename_from_ansi */
55#include "w32heap.h" 56#include "w32heap.h"
56#endif 57#endif
57 58
@@ -3128,7 +3129,14 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
3128 HDROP hdrop; 3129 HDROP hdrop;
3129 POINT p; 3130 POINT p;
3130 WORD num_files; 3131 WORD num_files;
3131 guichar_t *name; 3132 wchar_t name_w[MAX_PATH];
3133#ifdef NTGUI_UNICODE
3134 const int use_unicode = 1;
3135#else
3136 int use_unicode = w32_unicode_filenames;
3137 char name_a[MAX_PATH];
3138 char file[MAX_UTF8_PATH];
3139#endif
3132 int i, len; 3140 int i, len;
3133 3141
3134 result->kind = DRAG_N_DROP_EVENT; 3142 result->kind = DRAG_N_DROP_EVENT;
@@ -3153,17 +3161,30 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
3153 3161
3154 for (i = 0; i < num_files; i++) 3162 for (i = 0; i < num_files; i++)
3155 { 3163 {
3156 len = GUI_FN (DragQueryFile) (hdrop, i, NULL, 0); 3164 if (use_unicode)
3157 if (len <= 0) 3165 {
3158 continue; 3166 eassert (DragQueryFileW (hdrop, i, NULL, 0) < MAX_PATH);
3159 3167 /* If DragQueryFile returns zero, it failed to fetch a file
3160 name = alloca ((len + 1) * sizeof (*name)); 3168 name. */
3161 GUI_FN (DragQueryFile) (hdrop, i, name, len + 1); 3169 if (DragQueryFileW (hdrop, i, name_w, MAX_PATH) == 0)
3170 continue;
3162#ifdef NTGUI_UNICODE 3171#ifdef NTGUI_UNICODE
3163 files = Fcons (from_unicode_buffer (name), files); 3172 files = Fcons (from_unicode_buffer (name_w), files);
3164#else 3173#else
3165 files = Fcons (DECODE_FILE (build_string (name)), files); 3174 filename_from_utf16 (name_w, file);
3175 files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
3166#endif /* NTGUI_UNICODE */ 3176#endif /* NTGUI_UNICODE */
3177 }
3178#ifndef NTGUI_UNICODE
3179 else
3180 {
3181 eassert (DragQueryFileA (hdrop, i, NULL, 0) < MAX_PATH);
3182 if (DragQueryFileA (hdrop, i, name_a, MAX_PATH) == 0)
3183 continue;
3184 filename_from_ansi (name_a, file);
3185 files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
3186 }
3187#endif
3167 } 3188 }
3168 3189
3169 DragFinish (hdrop); 3190 DragFinish (hdrop);
@@ -6640,6 +6661,18 @@ X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
6640With MS Windows or Nextstep, the value is t. */); 6661With MS Windows or Nextstep, the value is t. */);
6641 Vx_toolkit_scroll_bars = Qt; 6662 Vx_toolkit_scroll_bars = Qt;
6642 6663
6664 DEFVAR_BOOL ("w32-unicode-filenames",
6665 w32_unicode_filenames,
6666 doc: /* Non-nil means use Unicode APIs when passing file names to the OS.
6667A value of nil means file names passed to the OS APIs and returned
6668from those APIs are encoded/decoded using the ANSI codepage
6669specified by `file-name-coding-system'.
6670
6671This variable is set to non-nil by default when Emacs runs on Windows
6672systems of the NT family, including W2K, XP, Vista, Windows 7 and
6673Windows 8. It is set to nil on Windows 9X. */);
6674 w32_unicode_filenames = 0;
6675
6643 /* Tell Emacs about this window system. */ 6676 /* Tell Emacs about this window system. */
6644 Fprovide (Qw32, Qnil); 6677 Fprovide (Qw32, Qnil);
6645} 6678}