diff options
| author | Eli Zaretskii | 2013-12-12 20:19:10 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-12-12 20:19:10 +0200 |
| commit | 01633a17e74e638f31ec71c3587481f0084574f2 (patch) | |
| tree | b41eb1c64d2c01cbf94130bcbf772c32f653333d /src | |
| parent | cf86e18b159f754d6e5537b7b9cbefc32297f7d2 (diff) | |
| parent | 893fcd38e9ef6bcb50dd9e9ed1de7caf194f8a83 (diff) | |
| download | emacs-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/ChangeLog | 125 | ||||
| -rw-r--r-- | src/coding.c | 49 | ||||
| -rw-r--r-- | src/coding.h | 24 | ||||
| -rw-r--r-- | src/dired.c | 4 | ||||
| -rw-r--r-- | src/emacs.c | 80 | ||||
| -rw-r--r-- | src/fileio.c | 55 | ||||
| -rw-r--r-- | src/filelock.c | 2 | ||||
| -rw-r--r-- | src/gnutls.c | 18 | ||||
| -rw-r--r-- | src/image.c | 15 | ||||
| -rw-r--r-- | src/msdos.c | 6 | ||||
| -rw-r--r-- | src/msdos.h | 2 | ||||
| -rw-r--r-- | src/sysdep.c | 4 | ||||
| -rw-r--r-- | src/termcap.c | 2 | ||||
| -rw-r--r-- | src/unexw32.c | 27 | ||||
| -rw-r--r-- | src/w32.c | 2599 | ||||
| -rw-r--r-- | src/w32.h | 21 | ||||
| -rw-r--r-- | src/w32fns.c | 667 | ||||
| -rw-r--r-- | src/w32notify.c | 96 | ||||
| -rw-r--r-- | src/w32proc.c | 137 | ||||
| -rw-r--r-- | src/w32term.c | 51 |
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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-12-12 Dmitry Antipov <dmantipov@yandex.ru> | 126 | 2013-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. */ | ||
| 9495 | Lisp_Object | ||
| 9496 | decode_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 | |||
| 9516 | Lisp_Object | ||
| 9517 | encode_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 | ||
| 9494 | DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string, | 9543 | DEFUN ("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); |
| 719 | extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object, | 705 | extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object, |
| 720 | bool); | 706 | bool); |
| 707 | extern Lisp_Object encode_file_name (Lisp_Object); | ||
| 708 | extern Lisp_Object decode_file_name (Lisp_Object); | ||
| 721 | extern Lisp_Object raw_text_coding_system (Lisp_Object); | 709 | extern Lisp_Object raw_text_coding_system (Lisp_Object); |
| 722 | extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object); | 710 | extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object); |
| 723 | extern Lisp_Object complement_process_encoding_system (Lisp_Object); | 711 | extern 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. |
| 5861 | If it is nil, `default-file-name-coding-system' (which see) is used. */); | 5878 | If it is nil, `default-file-name-coding-system' (which see) is used. |
| 5879 | |||
| 5880 | On MS-Windows, the value of this variable is largely ignored if | ||
| 5881 | \`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows | ||
| 5882 | behaves 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. | |||
| 5869 | This variable is set/changed by the command `set-language-environment'. | 5890 | This variable is set/changed by the command `set-language-environment'. |
| 5870 | User should not set this variable manually, | 5891 | User should not set this variable manually, |
| 5871 | instead use `file-name-coding-system' to get a constant encoding | 5892 | instead use `file-name-coding-system' to get a constant encoding |
| 5872 | of file names regardless of the current language environment. */); | 5893 | of file names regardless of the current language environment. |
| 5894 | |||
| 5895 | On MS-Windows, the value of this variable is largely ignored if | ||
| 5896 | \`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows | ||
| 5897 | behaves 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 | ||
| 3297 | void | 3297 | void |
| 3298 | dostounix_filename (char *p, int ignore) | 3298 | dostounix_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 | ||
| 30 | int getdefdir (int, char*); | 30 | int getdefdir (int, char*); |
| 31 | void unixtodos_filename (char *); | 31 | void unixtodos_filename (char *); |
| 32 | void dostounix_filename (char *, int); | 32 | void dostounix_filename (char *); |
| 33 | char *rootrelativepath (char *); | 33 | char *rootrelativepath (char *); |
| 34 | void init_environment (int, char **, int); | 34 | void init_environment (int, char **, int); |
| 35 | void internal_terminal_init (void); | 35 | void 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! */ | ||
| 123 | int | 125 | int |
| 124 | open_input_file (file_data *p_file, char *filename) | 126 | open_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 | |||
| 722 | unexec (const char *new_name, const char *old_name) | 724 | unexec (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 | ||
| @@ -248,7 +248,7 @@ static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *); | |||
| 248 | static int restore_privilege (TOKEN_PRIVILEGES *); | 248 | static int restore_privilege (TOKEN_PRIVILEGES *); |
| 249 | static BOOL WINAPI revert_to_self (void); | 249 | static BOOL WINAPI revert_to_self (void); |
| 250 | 250 | ||
| 251 | extern int sys_access (const char *, int); | 251 | static int sys_access (const char *, int); |
| 252 | extern void *e_malloc (size_t); | 252 | extern void *e_malloc (size_t); |
| 253 | extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, | 253 | extern 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; | |||
| 273 | static BOOL g_b_init_get_sid_sub_authority; | 273 | static BOOL g_b_init_get_sid_sub_authority; |
| 274 | static BOOL g_b_init_get_sid_sub_authority_count; | 274 | static BOOL g_b_init_get_sid_sub_authority_count; |
| 275 | static BOOL g_b_init_get_security_info; | 275 | static BOOL g_b_init_get_security_info; |
| 276 | static BOOL g_b_init_get_file_security; | 276 | static BOOL g_b_init_get_file_security_w; |
| 277 | static BOOL g_b_init_get_file_security_a; | ||
| 277 | static BOOL g_b_init_get_security_descriptor_owner; | 278 | static BOOL g_b_init_get_security_descriptor_owner; |
| 278 | static BOOL g_b_init_get_security_descriptor_group; | 279 | static BOOL g_b_init_get_security_descriptor_group; |
| 279 | static BOOL g_b_init_is_valid_sid; | 280 | static BOOL g_b_init_is_valid_sid; |
| @@ -292,12 +293,14 @@ static BOOL g_b_init_equal_sid; | |||
| 292 | static BOOL g_b_init_copy_sid; | 293 | static BOOL g_b_init_copy_sid; |
| 293 | static BOOL g_b_init_get_native_system_info; | 294 | static BOOL g_b_init_get_native_system_info; |
| 294 | static BOOL g_b_init_get_system_times; | 295 | static BOOL g_b_init_get_system_times; |
| 295 | static BOOL g_b_init_create_symbolic_link; | 296 | static BOOL g_b_init_create_symbolic_link_w; |
| 297 | static BOOL g_b_init_create_symbolic_link_a; | ||
| 296 | static BOOL g_b_init_get_security_descriptor_dacl; | 298 | static BOOL g_b_init_get_security_descriptor_dacl; |
| 297 | static BOOL g_b_init_convert_sd_to_sddl; | 299 | static BOOL g_b_init_convert_sd_to_sddl; |
| 298 | static BOOL g_b_init_convert_sddl_to_sd; | 300 | static BOOL g_b_init_convert_sddl_to_sd; |
| 299 | static BOOL g_b_init_is_valid_security_descriptor; | 301 | static BOOL g_b_init_is_valid_security_descriptor; |
| 300 | static BOOL g_b_init_set_file_security; | 302 | static BOOL g_b_init_set_file_security_w; |
| 303 | static BOOL g_b_init_set_file_security_a; | ||
| 301 | static BOOL g_b_init_get_adapters_info; | 304 | static 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 |
| 329 | const char * const LookupAccountSid_Name = "LookupAccountSidW"; | 332 | const char * const LookupAccountSid_Name = "LookupAccountSidW"; |
| 330 | const char * const GetFileSecurity_Name = "GetFileSecurityW"; | ||
| 331 | const char * const SetFileSecurity_Name = "SetFileSecurityW"; | ||
| 332 | #else | 333 | #else |
| 333 | const char * const LookupAccountSid_Name = "LookupAccountSidA"; | 334 | const char * const LookupAccountSid_Name = "LookupAccountSidA"; |
| 334 | const char * const GetFileSecurity_Name = "GetFileSecurityA"; | ||
| 335 | const char * const SetFileSecurity_Name = "SetFileSecurityA"; | ||
| 336 | #endif | 335 | #endif |
| 337 | typedef BOOL (WINAPI * LookupAccountSid_Proc) ( | 336 | typedef 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); |
| 359 | typedef BOOL (WINAPI * GetFileSecurity_Proc) ( | 358 | typedef 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); |
| 365 | typedef BOOL (WINAPI *SetFileSecurity_Proc) ( | 364 | typedef BOOL (WINAPI * GetFileSecurityA_Proc) ( |
| 366 | LPCTSTR lpFileName, | 365 | LPCSTR lpFileName, |
| 366 | SECURITY_INFORMATION RequestedInformation, | ||
| 367 | PSECURITY_DESCRIPTOR pSecurityDescriptor, | ||
| 368 | DWORD nLength, | ||
| 369 | LPDWORD lpnLengthNeeded); | ||
| 370 | typedef BOOL (WINAPI *SetFileSecurityW_Proc) ( | ||
| 371 | LPCWSTR lpFileName, | ||
| 372 | SECURITY_INFORMATION SecurityInformation, | ||
| 373 | PSECURITY_DESCRIPTOR pSecurityDescriptor); | ||
| 374 | typedef BOOL (WINAPI *SetFileSecurityA_Proc) ( | ||
| 375 | LPCSTR lpFileName, | ||
| 367 | SECURITY_INFORMATION SecurityInformation, | 376 | SECURITY_INFORMATION SecurityInformation, |
| 368 | PSECURITY_DESCRIPTOR pSecurityDescriptor); | 377 | PSECURITY_DESCRIPTOR pSecurityDescriptor); |
| 369 | typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( | 378 | typedef 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); |
| 428 | typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( | 437 | typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) ( |
| 429 | LPTSTR lpSymlinkFileName, | 438 | LPCWSTR lpSymlinkFileName, |
| 430 | LPTSTR lpTargetFileName, | 439 | LPCWSTR lpTargetFileName, |
| 440 | DWORD dwFlags); | ||
| 441 | typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) ( | ||
| 442 | LPCSTR lpSymlinkFileName, | ||
| 443 | LPCSTR lpTargetFileName, | ||
| 431 | DWORD dwFlags); | 444 | DWORD dwFlags); |
| 432 | typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( | 445 | typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( |
| 433 | LPCTSTR StringSecurityDescriptor, | 446 | LPCTSTR StringSecurityDescriptor, |
| @@ -679,64 +692,121 @@ get_security_info (HANDLE handle, | |||
| 679 | } | 692 | } |
| 680 | 693 | ||
| 681 | static BOOL WINAPI | 694 | static BOOL WINAPI |
| 682 | get_file_security (LPCTSTR lpFileName, | 695 | get_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 | ||
| 713 | static BOOL WINAPI | 755 | static BOOL WINAPI |
| 714 | set_file_security (LPCTSTR lpFileName, | 756 | set_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 | ||
| 742 | static BOOL WINAPI | 812 | static BOOL WINAPI |
| @@ -973,11 +1043,12 @@ get_system_times (LPFILETIME lpIdleTime, | |||
| 973 | } | 1043 | } |
| 974 | 1044 | ||
| 975 | static BOOLEAN WINAPI | 1045 | static BOOLEAN WINAPI |
| 976 | create_symbolic_link (LPTSTR lpSymlinkFilename, | 1046 | create_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 | ||
| 1185 | static 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. */ | ||
| 1401 | static 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. */ | ||
| 1405 | static int | ||
| 1406 | codepage_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 | |||
| 1460 | int | ||
| 1461 | filename_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 | |||
| 1487 | int | ||
| 1488 | filename_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 | |||
| 1514 | int | ||
| 1515 | filename_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 | |||
| 1549 | int | ||
| 1550 | filename_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. */ | ||
| 1581 | static char startup_dir[MAX_UTF8_PATH]; | ||
| 1186 | 1582 | ||
| 1187 | /* Get the current working directory. */ | 1583 | /* Get the current working directory. */ |
| 1188 | char * | 1584 | char * |
| @@ -1374,8 +1770,8 @@ getloadavg (double loadavg[], int nelem) | |||
| 1374 | static char dflt_passwd_name[PASSWD_FIELD_SIZE]; | 1770 | static char dflt_passwd_name[PASSWD_FIELD_SIZE]; |
| 1375 | static char dflt_passwd_passwd[PASSWD_FIELD_SIZE]; | 1771 | static char dflt_passwd_passwd[PASSWD_FIELD_SIZE]; |
| 1376 | static char dflt_passwd_gecos[PASSWD_FIELD_SIZE]; | 1772 | static char dflt_passwd_gecos[PASSWD_FIELD_SIZE]; |
| 1377 | static char dflt_passwd_dir[PASSWD_FIELD_SIZE]; | 1773 | static char dflt_passwd_dir[MAX_UTF8_PATH]; |
| 1378 | static char dflt_passwd_shell[PASSWD_FIELD_SIZE]; | 1774 | static char dflt_passwd_shell[MAX_UTF8_PATH]; |
| 1379 | 1775 | ||
| 1380 | static struct passwd dflt_passwd = | 1776 | static 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. */ | ||
| 1588 | static 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. */ |
| 1593 | static int | 2003 | static int |
| 1594 | max_filename_mbslen (void) | 2004 | max_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 | ||
| 1653 | static void | 2015 | static void |
| 1654 | normalize_filename (register char *fp, char path_sep, int multibyte) | 2016 | normalize_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. */ | ||
| 1732 | void | 2042 | void |
| 1733 | dostounix_filename (register char *p, int multibyte) | 2043 | dostounix_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. */ |
| 1739 | void | 2049 | void |
| 1740 | unixtodos_filename (register char *p) | 2050 | unixtodos_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. */ |
| 1774 | static int | 2084 | static int |
| 1775 | parse_root (char * name, char ** pPath) | 2085 | parse_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) | |||
| 1817 | static int | 2123 | static int |
| 1818 | get_long_basename (char * name, char * buf, int size) | 2124 | get_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 | ||
| 2238 | unsigned int | ||
| 2239 | w32_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 | |||
| 2269 | Lisp_Object | ||
| 2270 | ansi_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 | |||
| 1892 | static int | 2291 | static int |
| 1893 | is_unc_volume (const char *filename) | 2292 | is_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 | ||
| 2000 | char *get_emacs_configuration (void); | 2399 | /* The argv[] array holds ANSI-encoded strings, and so this function |
| 2001 | 2400 | works with ANS_encoded strings. */ | |
| 2002 | void | 2401 | void |
| 2003 | init_environment (char ** argv) | 2402 | init_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) | |||
| 2331 | char * | 2723 | char * |
| 2332 | emacs_root_dir (void) | 2724 | emacs_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 | |||
| 2351 | char * | ||
| 2352 | get_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 | |||
| 2444 | char * | ||
| 2445 | get_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 | |||
| 2649 | add_volume_info (char * root_dir, volume_info_data * info) | 2889 | add_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 * | |||
| 2661 | GetCachedVolumeInformation (char * root_dir) | 2902 | GetCachedVolumeInformation (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) | |||
| 2758 | static int | 3043 | static int |
| 2759 | get_volume_info (const char * name, const char ** pPath) | 3044 | get_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! */ | ||
| 2831 | const char * | 3087 | const char * |
| 2832 | map_w32_filename (const char * name, const char ** pPath) | 3088 | map_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 | ||
| 2946 | struct dirent dir_static; /* simulated directory contents */ | 3204 | struct dirent dir_static; /* simulated directory contents */ |
| 2947 | static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; | 3205 | static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; |
| 2948 | static int dir_is_fat; | 3206 | static int dir_is_fat; |
| 2949 | static char dir_pathname[MAXPATHLEN+1]; | 3207 | static char dir_pathname[MAX_UTF8_PATH]; |
| 2950 | static WIN32_FIND_DATA dir_find_data; | 3208 | static WIN32_FIND_DATAW dir_find_data_w; |
| 3209 | static WIN32_FIND_DATAA dir_find_data_a; | ||
| 3210 | #define DIR_FIND_DATA_W 1 | ||
| 3211 | #define DIR_FIND_DATA_A 2 | ||
| 3212 | static 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. */ |
| 2954 | static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; | 3216 | static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE; |
| 2955 | static HANDLE open_unc_volume (const char *); | 3217 | static HANDLE open_unc_volume (const char *); |
| 2956 | static char *read_unc_volume (HANDLE, char *, int); | 3218 | static void *read_unc_volume (HANDLE, wchar_t *, char *, int); |
| 2957 | static void close_unc_volume (HANDLE); | 3219 | static void close_unc_volume (HANDLE); |
| 2958 | 3220 | ||
| 2959 | DIR * | 3221 | DIR * |
| 2960 | opendir (const char *filename) | 3222 | sys_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 | ||
| 2999 | void | 3261 | void |
| 3000 | closedir (DIR *dirp) | 3262 | sys_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 | ||
| 3016 | struct dirent * | 3278 | struct dirent * |
| 3017 | readdir (DIR *dirp) | 3279 | sys_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 | ||
| 3121 | static HANDLE | 3394 | static HANDLE |
| 3122 | open_unc_volume (const char *path) | 3395 | open_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 | ||
| 3146 | static char * | 3443 | static void * |
| 3147 | read_unc_volume (HANDLE henum, char *readbuf, int size) | 3444 | read_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 | ||
| 3178 | static void | 3496 | static void |
| @@ -3203,13 +3521,12 @@ unc_volume_file_attributes (const char *path) | |||
| 3203 | static void | 3521 | static void |
| 3204 | logon_network_drive (const char *path) | 3522 | logon_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". */ | ||
| 3709 | static int | ||
| 3710 | sys_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) | |||
| 3334 | int | 3764 | int |
| 3335 | sys_chdir (const char * path) | 3765 | sys_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 | ||
| 3340 | int | 3786 | int |
| 3341 | sys_chmod (const char * path, int mode) | 3787 | sys_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 | ||
| 3347 | int | 3806 | int |
| 3348 | sys_creat (const char * path, int mode) | 3807 | sys_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 | ||
| 3353 | FILE * | 3826 | FILE * |
| @@ -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) | |||
| 3470 | int | 4003 | int |
| 3471 | sys_mkdir (const char * path) | 4004 | sys_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 | ||
| 3476 | int | 4024 | int |
| @@ -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 | |||
| 3555 | sys_rename_replace (const char *oldname, const char *newname, BOOL force) | 4119 | sys_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) | |||
| 3674 | int | 4283 | int |
| 3675 | sys_rmdir (const char * path) | 4284 | sys_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 | ||
| 3680 | int | 4304 | int |
| @@ -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 | ||
| 3690 | static FILETIME utc_base_ft; | 4328 | static 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). */ | ||
| 3763 | static unsigned | ||
| 3764 | hashval (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. */ | ||
| 3777 | static DWORD | ||
| 3778 | generate_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 | |||
| 3798 | static PSECURITY_DESCRIPTOR | 4393 | static PSECURITY_DESCRIPTOR |
| 3799 | get_file_security_desc_by_handle (HANDLE h) | 4394 | get_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. */ | ||
| 4005 | int w32_stat_get_owner_group; | 4601 | int 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 | ||
| 4011 | static int | 4608 | static int |
| 4012 | stat_worker (const char * path, struct stat * buf, int follow_symlinks) | 4609 | stat_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) | |||
| 4599 | int | 5253 | int |
| 4600 | symlink (char const *filename, char const *linkname) | 5254 | symlink (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 | |||
| 4751 | is_symlink (const char *filename) | 5381 | is_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, | |||
| 5024 | static char * | 5641 | static char * |
| 5025 | chase_symlinks (const char *file) | 5642 | chase_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) | |||
| 7753 | HMODULE | 8384 | HMODULE |
| 7754 | w32_delayed_load (Lisp_Object library_id) | 8385 | w32_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 */ |
| @@ -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. */ |
| 153 | extern BOOL w32_get_long_filename (char * name, char * buf, int size); | 147 | extern 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. */ | ||
| 150 | extern 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. */ |
| 156 | extern void prepare_standard_handles (int in, int out, | 153 | extern 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 **); | |||
| 181 | extern void check_windows_init_file (void); | 178 | extern void check_windows_init_file (void); |
| 182 | extern void syms_of_ntproc (void); | 179 | extern void syms_of_ntproc (void); |
| 183 | extern void syms_of_ntterm (void); | 180 | extern void syms_of_ntterm (void); |
| 184 | extern void dostounix_filename (register char *, int); | 181 | extern void dostounix_filename (register char *); |
| 185 | extern void unixtodos_filename (register char *); | 182 | extern void unixtodos_filename (register char *); |
| 183 | extern int filename_from_ansi (const char *, char *); | ||
| 184 | extern int filename_to_ansi (const char *, char *); | ||
| 185 | extern int filename_from_utf16 (const wchar_t *, char *); | ||
| 186 | extern int filename_to_utf16 (const char *, wchar_t *); | ||
| 187 | extern Lisp_Object ansi_encode_filename (Lisp_Object); | ||
| 188 | |||
| 186 | extern BOOL init_winsock (int load_now); | 189 | extern BOOL init_winsock (int load_now); |
| 187 | extern void srandom (int); | 190 | extern void srandom (int); |
| 188 | extern int random (void); | 191 | extern int random (void); |
| @@ -194,14 +197,10 @@ extern int pipe2 (int *, int); | |||
| 194 | extern void set_process_dir (char *); | 197 | extern void set_process_dir (char *); |
| 195 | extern int sys_spawnve (int, char *, char **, char **); | 198 | extern int sys_spawnve (int, char *, char **, char **); |
| 196 | extern void register_child (pid_t, int); | 199 | extern void register_child (pid_t, int); |
| 197 | extern void record_infile (pid_t, char *); | ||
| 198 | extern void record_pending_deletion (char *); | ||
| 199 | 200 | ||
| 200 | extern void sys_sleep (int); | 201 | extern void sys_sleep (int); |
| 201 | extern int sys_link (const char *, const char *); | 202 | extern 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 | §ors_per_cluster, | 7513 | result = GetDiskFreeSpaceW (rootname_w, |
| 7193 | &bytes_per_sector, | 7514 | §ors_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 | §ors_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 | ||
| 7210 | DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name, | 7540 | DEFUN ("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 | |||
| 490 | generate notifications correctly, though. */) | 518 | generate 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. */ | ||
| 1079 | static char * process_dir; | 1064 | static char * process_dir; |
| 1080 | 1065 | ||
| 1081 | static BOOL | 1066 | static 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. */ | ||
| 1186 | void | ||
| 1187 | record_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. */ | ||
| 1208 | void | ||
| 1209 | record_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. */ |
| 1225 | static void | 1178 | static void |
| 1226 | reap_subprocess (child_process *cp) | 1179 | reap_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. */ | ||
| 1430 | static void | 1385 | static void |
| 1431 | w32_executable_type (char * filename, | 1386 | w32_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. | |||
| 2690 | All path elements in FILENAME are converted to their long names. */) | 2672 | All 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 | ||
| 2719 | DEFUN ("w32-set-process-priority", Fw32_set_process_priority, | 2702 | DEFUN ("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. | |||
| 6640 | With MS Windows or Nextstep, the value is t. */); | 6661 | With 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. | ||
| 6667 | A value of nil means file names passed to the OS APIs and returned | ||
| 6668 | from those APIs are encoded/decoded using the ANSI codepage | ||
| 6669 | specified by `file-name-coding-system'. | ||
| 6670 | |||
| 6671 | This variable is set to non-nil by default when Emacs runs on Windows | ||
| 6672 | systems of the NT family, including W2K, XP, Vista, Windows 7 and | ||
| 6673 | Windows 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 | } |