emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r115490: Support MS-Windows file names that use char


From: Eli Zaretskii
Subject: [Emacs-diffs] trunk r115490: Support MS-Windows file names that use characters outside of ANSI codepage.
Date: Thu, 12 Dec 2013 18:23:11 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 115490 [merge]
revision-id: address@hidden
parent: address@hidden
parent: address@hidden
fixes bug: http://debbugs.gnu.org/7100
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Thu 2013-12-12 20:19:10 +0200
message:
  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.
modified:
  doc/emacs/ChangeLog            changelog-20091113204419-o5vbwnq5f7feedwu-6227
  doc/emacs/mule.texi            mule.texi-20091113204419-o5vbwnq5f7feedwu-6270
  doc/lispref/ChangeLog          changelog-20091113204419-o5vbwnq5f7feedwu-6155
  doc/lispref/nonascii.texi      
nonascii.texi-20091113204419-o5vbwnq5f7feedwu-6202
  etc/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1485
  etc/NEWS                       news-20100311060928-aoit31wvzf25yr1z-1
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/dnd.el                    dnd.el-20091113204419-o5vbwnq5f7feedwu-3401
  lisp/net/browse-url.el         
browseurl.el-20091113204419-o5vbwnq5f7feedwu-1785
  lisp/startup.el                startup.el-20091113204419-o5vbwnq5f7feedwu-260
  lisp/term/w32-win.el           w32win.el-20091113204419-o5vbwnq5f7feedwu-943
  nt/ChangeLog                   changelog-20091113204419-o5vbwnq5f7feedwu-1545
  nt/inc/dirent.h                ndir.h-20091113204419-o5vbwnq5f7feedwu-417
  nt/inc/ms-w32.h                msw32.h-20091113204419-o5vbwnq5f7feedwu-807
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/coding.c                   coding.c-20091113204419-o5vbwnq5f7feedwu-1077
  src/coding.h                   coding.h-20091113204419-o5vbwnq5f7feedwu-1078
  src/dired.c                    dired.c-20091113204419-o5vbwnq5f7feedwu-171
  src/emacs.c                    emacs.c-20091113204419-o5vbwnq5f7feedwu-241
  src/fileio.c                   fileio.c-20091113204419-o5vbwnq5f7feedwu-210
  src/filelock.c                 filelock.c-20091113204419-o5vbwnq5f7feedwu-179
  src/gnutls.c                   gnutls.c-20100926054902-dzayyj6wycit6kzn-3
  src/image.c                    image.c-20091113204419-o5vbwnq5f7feedwu-2969
  src/msdos.c                    msdos.c-20091113204419-o5vbwnq5f7feedwu-656
  src/msdos.h                    msdos.h-20091113204419-o5vbwnq5f7feedwu-657
  src/sysdep.c                   sysdep.c-20091113204419-o5vbwnq5f7feedwu-448
  src/termcap.c                  termcap.c-20091113204419-o5vbwnq5f7feedwu-775
  src/unexw32.c                  unexw32.c-20091113204419-o5vbwnq5f7feedwu-887
  src/w32.c                      w32.c-20091113204419-o5vbwnq5f7feedwu-808
  src/w32.h                      w32.h-20091113204419-o5vbwnq5f7feedwu-809
  src/w32fns.c                   w32fns.c-20091113204419-o5vbwnq5f7feedwu-945
  src/w32notify.c                w32notify.c-20121007123611-xyh65j2ka2vm684f-1
  src/w32proc.c                  w32proc.c-20091113204419-o5vbwnq5f7feedwu-814
  src/w32term.c                  w32term.c-20091113204419-o5vbwnq5f7feedwu-950
=== modified file 'doc/emacs/ChangeLog'
--- a/doc/emacs/ChangeLog       2013-12-12 03:37:38 +0000
+++ b/doc/emacs/ChangeLog       2013-12-12 18:19:10 +0000
@@ -1,3 +1,8 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       * mule.texi (File Name Coding): Document file-name encoding
+       peculiarities on MS-Windows.
+
 2013-12-12  Glenn Morris  <address@hidden>
 
        * emacs.texi: Sync direntry with info/dir version.

=== modified file 'doc/emacs/mule.texi'
--- a/doc/emacs/mule.texi       2013-07-31 13:11:47 +0000
+++ b/doc/emacs/mule.texi       2013-12-07 16:51:33 +0000
@@ -1130,6 +1130,21 @@
 file names are not encoded specially; they appear in the file system
 using the internal Emacs representation.
 
address@hidden file-name encoding, MS-Windows
address@hidden w32-unicode-filenames
+  When Emacs runs on MS-Windows versions that are descendants of the
+NT family (Windows 2000, XP, Vista, Windows 7, and Windows 8), the
+value of @code{file-name-coding-system} is largely ignored, as Emacs
+by default uses APIs that allow to pass Unicode file names directly.
+By contrast, on Windows 9X, file names are encoded using
address@hidden, which should be set to the codepage
+(@pxref{Coding Systems, codepage}) pertinent for the current system
+locale.  The value of the variable @code{w32-unicode-filenames}
+controls whether Emacs uses the Unicode APIs when it calls OS
+functions that accept file names.  This variable is set by the startup
+code to @code{nil} on Windows 9X, and to @code{t} on newer versions of
+MS-Windows.
+
   @strong{Warning:} if you change @code{file-name-coding-system} (or the
 language environment) in the middle of an Emacs session, problems can
 result if you have already visited files whose names were encoded using

=== modified file 'doc/lispref/ChangeLog'
--- a/doc/lispref/ChangeLog     2013-12-12 03:37:38 +0000
+++ b/doc/lispref/ChangeLog     2013-12-12 18:19:10 +0000
@@ -1,3 +1,8 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       * nonascii.texi (Encoding and I/O): Document file-name encoding
+       peculiarities on MS-Windows.
+
 2013-12-12  Glenn Morris  <address@hidden>
 
        * elisp.texi: Sync direntry with info/dir version.

=== modified file 'doc/lispref/nonascii.texi'
--- a/doc/lispref/nonascii.texi 2013-10-25 12:23:07 +0000
+++ b/doc/lispref/nonascii.texi 2013-12-07 16:51:33 +0000
@@ -1108,6 +1108,16 @@
 an error.  If such a problem happens, use @kbd{C-x C-w} to specify a
 new file name for that buffer.
 
address@hidden file-name encoding, MS-Windows
+  On Windows 2000 and later, Emacs by default uses Unicode APIs to
+pass file names to the OS, so the value of
address@hidden is largely ignored.  Lisp applications
+that need to encode or decode file names on the Lisp level should use
address@hidden coding-system when @code{system-type} is
address@hidden; the conversion of UTF-8 encoded file names to the
+encoding appropriate for communicating with the OS is performed
+internally by Emacs.
+
 @node Lisp and Coding Systems
 @subsection Coding Systems in Lisp
 

=== modified file 'etc/ChangeLog'
--- a/etc/ChangeLog     2013-11-23 14:19:32 +0000
+++ b/etc/ChangeLog     2013-12-12 18:19:10 +0000
@@ -1,3 +1,8 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       * NEWS: Mention support on MS-Windows of file names outside of the
+       current locale.
+
 2013-11-23  Xue Fuqiao  <address@hidden>
 
        * TODO: Minor update.

=== modified file 'etc/NEWS'
--- a/etc/NEWS  2013-12-12 00:42:16 +0000
+++ b/etc/NEWS  2013-12-12 18:19:10 +0000
@@ -1001,6 +1001,14 @@
 need to set any variables due to this change.)
 
 +++
+** Emacs on Windows 2000 and later can now access files and directories
+whose names cannot be encoded in the current system codepage.
+
+The new variable `w32-unicode-filenames' controls this feature: if it
+is t, Emacs uses Unicode APIs to pass file names to system calls,
+which lifts the limitation of file names to the current locale.
+
++++
 ** The "generate a backtrace on fatal error" feature now works on MS Windows.
 The backtrace is written to the 'emacs_backtrace.txt' file in the
 directory where Emacs was running.

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-12-12 05:37:09 +0000
+++ b/lisp/ChangeLog    2013-12-12 18:19:10 +0000
@@ -1,3 +1,12 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       * term/w32-win.el (w32-handle-dropped-file):
+       * startup.el (normal-top-level):
+       * net/browse-url.el (browse-url-file-url):
+       * dnd.el (dnd-get-local-file-name): On MS-Windows, encode and
+       decode file names using 'utf-8' rather than
+       file-name-coding-system.
+
 2013-12-12  Fabián Ezequiel Gallina  <address@hidden>
 
        * progmodes/python.el (python-indent-context)

=== modified file 'lisp/dnd.el'
--- a/lisp/dnd.el       2013-01-01 09:11:05 +0000
+++ b/lisp/dnd.el       2013-12-03 12:21:13 +0000
@@ -152,10 +152,13 @@
   (let ((f (cond ((string-match "^file:///" uri)       ; XDND format.
                  (substring uri (1- (match-end 0))))
                 ((string-match "^file:" uri)           ; Old KDE, Motif, Sun
-                 (substring uri (match-end 0))))))
-    (and f (setq f (decode-coding-string (dnd-unescape-uri f)
-                                         (or file-name-coding-system
-                                             
default-file-name-coding-system))))
+                 (substring uri (match-end 0)))))
+       (coding (if (equal system-type 'windows-nt)
+                   ;; W32 pretends that file names are UTF-8 encoded.
+                   'utf-8
+                 (or file-name-coding-system
+                     default-file-name-coding-system))))
+    (and f (setq f (decode-coding-string (dnd-unescape-uri f) coding)))
     (when (and f must-exist (not (file-readable-p f)))
       (setq f nil))
     f))

=== modified file 'lisp/net/browse-url.el'
--- a/lisp/net/browse-url.el    2013-09-05 03:30:07 +0000
+++ b/lisp/net/browse-url.el    2013-12-03 12:21:13 +0000
@@ -723,9 +723,12 @@
 (defun browse-url-file-url (file)
   "Return the URL corresponding to FILE.
 Use variable `browse-url-filename-alist' to map filenames to URLs."
-  (let ((coding (and (default-value 'enable-multibyte-characters)
-                    (or file-name-coding-system
-                        default-file-name-coding-system))))
+  (let ((coding (if (equal system-type 'windows-nt)
+                   ;; W32 pretends that file names are UTF-8 encoded.
+                   'utf-8
+                 (and (default-value 'enable-multibyte-characters)
+                      (or file-name-coding-system
+                          default-file-name-coding-system)))))
     (if coding (setq file (encode-coding-string file coding))))
   (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
   (dolist (map browse-url-filename-alist)

=== modified file 'lisp/startup.el'
--- a/lisp/startup.el   2013-12-01 02:04:46 +0000
+++ b/lisp/startup.el   2013-12-09 17:33:01 +0000
@@ -533,43 +533,45 @@
     ;; for many other file-name variables and directory lists, so it
     ;; is important to decode it ASAP.
     (when locale-coding-system
-      (save-excursion
-       (dolist (elt (buffer-list))
-         (set-buffer elt)
-         (if default-directory
-             (setq default-directory
-                   (decode-coding-string default-directory
-                                         locale-coding-system t)))))
+      (let ((coding (if (eq system-type 'windows-nt)
+                       ;; MS-Windows build converts all file names to
+                       ;; UTF-8 during startup.
+                       'utf-8
+                     locale-coding-system)))
+       (save-excursion
+         (dolist (elt (buffer-list))
+           (set-buffer elt)
+           (if default-directory
+               (setq default-directory
+                     (decode-coding-string default-directory coding t)))))
 
-      ;; Decode all the important variables and directory lists, now
-      ;; that we know the locale's encoding.  This is because the
-      ;; values of these variables are until here unibyte undecoded
-      ;; strings created by build_unibyte_string.  data-directory in
-      ;; particular is used to construct many other standard directory
-      ;; names, so it must be decoded ASAP.
-      ;; Note that charset-map-path cannot be decoded here, since we
-      ;; could then be trapped in infinite recursion below, when we
-      ;; load subdirs.el, because encoding a directory name might need
-      ;; to load a charset map, which will want to encode
-      ;; charset-map-path, which will want to load the same charset
-      ;; map...  So decoding of charset-map-path is delayed until
-      ;; further down below.
-      (dolist (pathsym '(load-path exec-path))
-       (let ((path (symbol-value pathsym)))
-         (if (listp path)
-             (set pathsym (mapcar (lambda (dir)
-                                    (decode-coding-string
-                                     dir
-                                     locale-coding-system t))
-                               path)))))
-      (dolist (filesym '(data-directory doc-directory exec-directory
-                                       installation-directory
-                                       invocation-directory invocation-name
-                                       source-directory
-                                       shared-game-score-directory))
-       (let ((file (symbol-value filesym)))
-         (if (stringp file)
-             (set filesym (decode-coding-string file locale-coding-system 
t))))))
+       ;; Decode all the important variables and directory lists, now
+       ;; that we know the locale's encoding.  This is because the
+       ;; values of these variables are until here unibyte undecoded
+       ;; strings created by build_unibyte_string.  data-directory in
+       ;; particular is used to construct many other standard
+       ;; directory names, so it must be decoded ASAP.  Note that
+       ;; charset-map-path cannot be decoded here, since we could
+       ;; then be trapped in infinite recursion below, when we load
+       ;; subdirs.el, because encoding a directory name might need to
+       ;; load a charset map, which will want to encode
+       ;; charset-map-path, which will want to load the same charset
+       ;; map...  So decoding of charset-map-path is delayed until
+       ;; further down below.
+       (dolist (pathsym '(load-path exec-path))
+         (let ((path (symbol-value pathsym)))
+           (if (listp path)
+               (set pathsym (mapcar (lambda (dir)
+                                      (decode-coding-string dir coding t))
+                                    path)))))
+       (dolist (filesym '(data-directory doc-directory exec-directory
+                                         installation-directory
+                                         invocation-directory invocation-name
+                                         source-directory
+                                         shared-game-score-directory))
+         (let ((file (symbol-value filesym)))
+           (if (stringp file)
+               (set filesym (decode-coding-string file coding t)))))))
 
     (let ((dir default-directory))
       (with-current-buffer "*Messages*"
@@ -599,12 +601,13 @@
     ;; need for encoding them are already loaded, we are ready to
     ;; decode charset-map-path.
     (if (listp charset-map-path)
-       (setq charset-map-path
-             (mapcar (lambda (dir)
-                       (decode-coding-string
-                        dir
-                        locale-coding-system t))
-                     charset-map-path)))
+       (let ((coding (if (eq system-type 'windows-nt)
+                         'utf-8
+                       locale-coding-system)))
+         (setq charset-map-path
+               (mapcar (lambda (dir)
+                         (decode-coding-string dir coding t))
+                       charset-map-path))))
     (setq default-directory (abbreviate-file-name default-directory))
     (let ((old-face-font-rescale-alist face-font-rescale-alist))
       (unwind-protect

=== modified file 'lisp/term/w32-win.el'
--- a/lisp/term/w32-win.el      2013-11-01 09:04:16 +0000
+++ b/lisp/term/w32-win.el      2013-12-03 12:21:13 +0000
@@ -110,8 +110,13 @@
   (let ((f (if (eq system-type 'cygwin)
                (cygwin-convert-file-name-from-windows file-name t)
              (subst-char-in-string ?\\ ?/ file-name)))
-        (coding (or file-name-coding-system
-                    default-file-name-coding-system)))
+        (coding (if (eq system-type 'windows-nt)
+                   ;; Native w32 build pretends that its file names
+                   ;; are encoded in UTF-8, and converts to the
+                   ;; appropriate encoding internally.
+                   'utf-8
+                 (or file-name-coding-system
+                     default-file-name-coding-system))))
 
     (setq file-name
           (mapconcat 'url-hexify-string

=== modified file 'nt/ChangeLog'
--- a/nt/ChangeLog      2013-11-27 06:15:06 +0000
+++ b/nt/ChangeLog      2013-12-12 18:19:10 +0000
@@ -1,3 +1,10 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       * inc/ms-w32.h (MAX_UTF8_PATH): New macro.
+       (opendir, closedir, readdir, seekdir): Redirect to replacement
+       functions.
+       * inc/dirent.h: Make d_name[] be MAXNAMELEN*4 characters long.
+
 2013-11-27  Glenn Morris  <address@hidden>
 
        * README.W32:

=== modified file 'nt/inc/dirent.h'
--- a/nt/inc/dirent.h   2013-10-12 13:11:14 +0000
+++ b/nt/inc/dirent.h   2013-11-09 12:49:02 +0000
@@ -40,7 +40,7 @@
        __int64         d_time_write;
        _fsize_t        d_size;
 #endif
-       char            d_name[MAXNAMLEN+1];    /* name of file */
+       char            d_name[MAXNAMLEN * 4 + 1];      /* name of file */
        };
 
 typedef struct

=== modified file 'nt/inc/ms-w32.h'
--- a/nt/inc/ms-w32.h   2013-11-29 01:22:40 +0000
+++ b/nt/inc/ms-w32.h   2013-12-07 17:21:57 +0000
@@ -152,6 +152,9 @@
 #define MAXPATHLEN      _MAX_PATH
 #endif
 
+/* This is used to hold UTF-8 encoded file names.  */
+#define MAX_UTF8_PATH   (MAXPATHLEN * 4)
+
 #ifdef HAVE_NTGUI
 # ifndef HAVE_WINDOW_SYSTEM
 #  define HAVE_WINDOW_SYSTEM 1
@@ -218,6 +221,14 @@
 #define strerror sys_strerror
 #undef unlink
 #define unlink  sys_unlink
+#undef opendir
+#define opendir sys_opendir
+#undef closedir
+#define closedir sys_closedir
+#undef readdir
+#define readdir sys_readdir
+#undef seekdir
+#define seekdir sys_seekdir
 /* This prototype is needed because some files include config.h
    _after_ the standard headers, so sys_unlink gets no prototype from
    stdio.h or io.h.  */

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-12-12 14:26:06 +0000
+++ b/src/ChangeLog     2013-12-12 18:19:10 +0000
@@ -1,3 +1,128 @@
+2013-12-12  Eli Zaretskii  <address@hidden>
+
+       Support file names on MS-Windows that use characters outside of
+       the current system codepage.  (Bug#7100)
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * 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.
+
+       * dired.c (file_attributes): Use build_unibyte_string explicitly
+       to make Lisp strings from user and group names.
+
+       * coding.h (ENCODE_FILE, DECODE_FILE): Just call encode_file and
+       decode_file.
+
+       * coding.c (decode_file_name, encode_file_name): New functions.
+
+       * termcap.c (tgetent): Adapt to the change in arguments of
+       dostounix_filename.
+
+       * sysdep.c (sys_subshell) [WINDOWSNT]: Use MAX_UTF8_PATH for file
+       names.
+
+       * msdos.c (dostounix_filename, init_environment): Adapt to the
+       change in arguments of dostounix_filename.
+
+       * image.c (xpm_load, tiff_load, gif_load, imagemagick_load)
+       [WINDOWSNT]: Encode file names passed to the image libraries in
+       ANSI codepage.
+
+       * gnutls.c (Fgnutls_boot): Encode all file names passed to GnuTLS.
+       [WINDOWSNT]: Convert file names to the current ANSI codepage.
+
+       * filelock.c (lock_file) [WINDOWSNT]: Adapt to the change in
+       arguments of dostounix_filename.
+
 2013-12-12  Dmitry Antipov  <address@hidden>
 
        * font.h (struct font_entity) [HAVE_NS]: New field to record

=== modified file 'src/coding.c'
--- a/src/coding.c      2013-11-18 16:29:49 +0000
+++ b/src/coding.c      2013-11-18 16:45:48 +0000
@@ -9490,6 +9490,55 @@
   return code_convert_string (string, coding_system, Qt, encodep, 0, 1);
 }
 
+/* Encode or decode a file name, to or from a unibyte string suitable
+   for passing to C library functions.  */
+Lisp_Object
+decode_file_name (Lisp_Object fname)
+{
+#ifdef WINDOWSNT
+  /* The w32 build pretends to use UTF-8 for file-name encoding, and
+     converts the file names either to UTF-16LE or to the system ANSI
+     codepage internally, depending on the underlying OS; see w32.c.  */
+  if (! NILP (Fcoding_system_p (Qutf_8)))
+    return code_convert_string_norecord (fname, Qutf_8, 0);
+  return fname;
+#else  /* !WINDOWSNT */
+  if (! NILP (Vfile_name_coding_system))
+    return code_convert_string_norecord (fname, Vfile_name_coding_system, 0);
+  else if (! NILP (Vdefault_file_name_coding_system))
+    return code_convert_string_norecord (fname,
+                                        Vdefault_file_name_coding_system, 0);
+  else
+    return fname;
+#endif
+}
+
+Lisp_Object
+encode_file_name (Lisp_Object fname)
+{
+  /* This is especially important during bootstrap and dumping, when
+     file-name encoding is not yet known, and therefore any non-ASCII
+     file names are unibyte strings, and could only be thrashed if we
+     try to encode them.  */
+  if (!STRING_MULTIBYTE (fname))
+    return fname;
+#ifdef WINDOWSNT
+  /* The w32 build pretends to use UTF-8 for file-name encoding, and
+     converts the file names either to UTF-16LE or to the system ANSI
+     codepage internally, depending on the underlying OS; see w32.c.  */
+  if (! NILP (Fcoding_system_p (Qutf_8)))
+    return code_convert_string_norecord (fname, Qutf_8, 1);
+  return fname;
+#else  /* !WINDOWSNT */
+  if (! NILP (Vfile_name_coding_system))
+    return code_convert_string_norecord (fname, Vfile_name_coding_system, 1);
+  else if (! NILP (Vdefault_file_name_coding_system))
+    return code_convert_string_norecord (fname,
+                                        Vdefault_file_name_coding_system, 1);
+  else
+    return fname;
+#endif
+}
 
 DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string,
        2, 4, 0,

=== modified file 'src/coding.h'
--- a/src/coding.h      2013-11-04 17:30:33 +0000
+++ b/src/coding.h      2013-11-18 16:45:48 +0000
@@ -670,27 +670,13 @@
     (code) = (s1 << 8) | s2;                           \
   } while (0)
 
-/* Encode the file name NAME using the specified coding system for
-   file names, if any.  If NAME is a unibyte string, return NAME.  */
-#define ENCODE_FILE(name)                                              \
-    (! STRING_MULTIBYTE (name)                                         \
-     ? name                                                            \
-     : (! NILP (Vfile_name_coding_system)                              \
-       ? code_convert_string_norecord (name, Vfile_name_coding_system, 1) \
-       : (! NILP (Vdefault_file_name_coding_system)                    \
-          ? code_convert_string_norecord (name, 
Vdefault_file_name_coding_system, 1) \
-          : name)))
-
+/* Encode the file name NAME using the specified coding system
+   for file names, if any.  */
+#define ENCODE_FILE(NAME)  encode_file_name (NAME)
 
 /* Decode the file name NAME using the specified coding system
    for file names, if any.  */
-#define DECODE_FILE(name)                                                 \
-  (! NILP (Vfile_name_coding_system)                                      \
-   ? code_convert_string_norecord (name, Vfile_name_coding_system, 0)     \
-   : (! NILP (Vdefault_file_name_coding_system)                                
   \
-      ? code_convert_string_norecord (name, Vdefault_file_name_coding_system, 
0) \
-      : name))
-
+#define DECODE_FILE(NAME)  decode_file_name (NAME)
 
 /* Encode the string STR using the specified coding system
    for system functions, if any.  */
@@ -718,6 +704,8 @@
                                         Lisp_Object, bool, bool, bool);
 extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object,
                                                  bool);
+extern Lisp_Object encode_file_name (Lisp_Object);
+extern Lisp_Object decode_file_name (Lisp_Object);
 extern Lisp_Object raw_text_coding_system (Lisp_Object);
 extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object);
 extern Lisp_Object complement_process_encoding_system (Lisp_Object);

=== modified file 'src/dired.c'
--- a/src/dired.c       2013-09-21 11:48:19 +0000
+++ b/src/dired.c       2013-11-18 14:29:23 +0000
@@ -958,11 +958,11 @@
       unblock_input ();
     }
   if (uname)
-    values[2] = DECODE_SYSTEM (build_string (uname));
+    values[2] = DECODE_SYSTEM (build_unibyte_string (uname));
   else
     values[2] = make_fixnum_or_float (s.st_uid);
   if (gname)
-    values[3] = DECODE_SYSTEM (build_string (gname));
+    values[3] = DECODE_SYSTEM (build_unibyte_string (gname));
   else
     values[3] = make_fixnum_or_float (s.st_gid);
 

=== modified file 'src/emacs.c'
--- a/src/emacs.c       2013-12-08 12:18:13 +0000
+++ b/src/emacs.c       2013-12-09 17:20:34 +0000
@@ -36,6 +36,7 @@
 #ifdef WINDOWSNT
 #include <fcntl.h>
 #include <sys/socket.h>
+#include <mbstring.h>
 #include "w32.h"
 #include "w32heap.h"
 #endif
@@ -393,7 +394,20 @@
   initial_argv = argv;
   initial_argc = argc;
 
+#ifdef WINDOWSNT
+  /* Must use argv[0] converted to UTF-8, as it begets many standard
+     file and directory names.  */
+  {
+    char argv0[MAX_UTF8_PATH];
+
+    if (filename_from_ansi (argv[0], argv0) == 0)
+      raw_name = build_unibyte_string (argv0);
+    else
+      raw_name = build_unibyte_string (argv[0]);
+  }
+#else
   raw_name = build_unibyte_string (argv[0]);
+#endif
 
   /* Add /: to the front of the name
      if it would otherwise be treated as magic.  */
@@ -795,6 +809,14 @@
 
   if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
     {
+#ifdef WINDOWSNT
+      /* argv[] array is kept in its original ANSI codepage encoding,
+        we need to convert to UTF-8, for chdir to work.  */
+      char newdir[MAX_UTF8_PATH];
+
+      filename_from_ansi (ch_to_dir, newdir);
+      ch_to_dir = newdir;
+#endif
       original_pwd = get_current_dir_name ();
       if (chdir (ch_to_dir) != 0)
         {
@@ -1539,7 +1561,16 @@
       char *file;
       /* Handle -l loadup, args passed by Makefile.  */
       if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args))
-       Vtop_level = list2 (intern_c_string ("load"), build_string (file));
+       {
+#ifdef WINDOWSNT
+         char file_utf8[MAX_UTF8_PATH];
+
+         if (filename_from_ansi (file, file_utf8) == 0)
+           file = file_utf8;
+#endif
+         Vtop_level = list2 (intern_c_string ("load"),
+                             build_unibyte_string (file));
+       }
       /* Unless next switch is -nl, load "loadup.el" first thing.  */
       if (! no_loadup)
        Vtop_level = list2 (intern_c_string ("load"),
@@ -2185,9 +2216,15 @@
   Lisp_Object empty_element = empty ? Qnil : build_string (".");
 #ifdef WINDOWSNT
   bool defaulted = 0;
-  const char *emacs_dir = egetenv ("emacs_dir");
   static const char *emacs_dir_env = "%emacs_dir%/";
   const size_t emacs_dir_len = strlen (emacs_dir_env);
+  const char *edir = egetenv ("emacs_dir");
+  char emacs_dir[MAX_UTF8_PATH];
+
+  /* egetenv looks in process-environment, which holds the variables
+     in their original system-locale encoding.  We need emacs_dir to
+     be in UTF-8.  */
+  filename_from_ansi (edir, emacs_dir);
 #endif
 
   /* It's okay to use getenv here, because this function is only used
@@ -2208,9 +2245,44 @@
   /* Ensure values from the environment use the proper directory separator.  */
   if (path)
     {
-      char *path_copy = alloca (strlen (path) + 1);
-      strcpy (path_copy, path);
-      dostounix_filename (path_copy, 0);
+      char *path_copy;
+
+#ifdef WINDOWSNT
+      char *path_utf8, *q, *d;
+      int cnv_result;
+
+      /* Convert each element of PATH to UTF-8.  */
+      p = path_copy = alloca (strlen (path) + 1);
+      strcpy (path_copy, path);
+      d = path_utf8 = alloca (4 * strlen (path) + 1);
+      *d = '\0';
+      do {
+       q = _mbschr (p, SEPCHAR);
+       if (q)
+         *q = '\0';
+       cnv_result = filename_from_ansi (p, d);
+       if (q)
+         {
+           *q++ = SEPCHAR;
+           p = q;
+           /* If conversion of this PATH elements fails, make sure
+              destination pointer will stay put, thus effectively
+              ignoring the offending element.  */
+           if (cnv_result == 0)
+             {
+               d += strlen (d);
+               *d++ = SEPCHAR;
+             }
+         }
+       else if (cnv_result != 0 && d > path_utf8)
+         d[-1] = '\0'; /* remove last semi-colon and null-terminate PATH */
+      } while (q);
+      path_copy = path_utf8;
+#else  /* MSDOS */
+      path_copy = alloca (strlen (path) + 1);
+      strcpy (path_copy, path);
+#endif
+      dostounix_filename (path_copy);
       path = path_copy;
     }
 #endif

=== modified file 'src/fileio.c'
--- a/src/fileio.c      2013-11-27 16:08:53 +0000
+++ b/src/fileio.c      2013-12-12 18:19:10 +0000
@@ -460,7 +460,8 @@
            strcat (res, "/");
          beg = res;
          p = beg + strlen (beg);
-         dostounix_filename (beg, 0);
+         dostounix_filename (beg);
+         /* FIXME: Figure out the multibyte vs unibyte stuff here.  */
          tem_fn = make_specified_string (beg, -1, p - beg,
                                          STRING_MULTIBYTE (filename));
        }
@@ -471,7 +472,7 @@
   else if (STRING_MULTIBYTE (filename))
     {
       tem_fn = make_specified_string (beg, -1, p - beg, 1);
-      dostounix_filename (SSDATA (tem_fn), 1);
+      dostounix_filename (SSDATA (tem_fn));
 #ifdef WINDOWSNT
       if (!NILP (Vw32_downcase_file_names))
        tem_fn = Fdowncase (tem_fn);
@@ -479,7 +480,7 @@
     }
   else
     {
-      dostounix_filename (beg, 0);
+      dostounix_filename (beg);
       tem_fn = make_specified_string (beg, -1, p - beg, 0);
     }
   return tem_fn;
@@ -583,7 +584,7 @@
     dst[srclen++] = DIRECTORY_SEP;
   dst[srclen] = 0;
 #ifdef DOS_NT
-  dostounix_filename (dst, multibyte);
+  dostounix_filename (dst);
 #endif
   return srclen;
 }
@@ -652,7 +653,7 @@
   memcpy (dst, src, srclen);
   dst[srclen] = 0;
 #ifdef DOS_NT
-  dostounix_filename (dst, multibyte);
+  dostounix_filename (dst);
 #endif
   return srclen;
 }
@@ -1101,7 +1102,7 @@
 #ifdef DOS_NT
          /* Make sure directories are all separated with /, but
             avoid allocation of a new string when not required. */
-         dostounix_filename (nm, multibyte);
+         dostounix_filename (nm);
 #ifdef WINDOWSNT
          if (IS_DIRECTORY_SEP (nm[1]))
            {
@@ -1162,7 +1163,18 @@
          nm++;
          /* `egetenv' may return a unibyte string, which will bite us since
             we expect the directory to be multibyte.  */
-         tem = build_string (newdir);
+#ifdef WINDOWSNT
+         if (newdir[0])
+           {
+             char newdir_utf8[MAX_UTF8_PATH];
+
+             filename_from_ansi (newdir, newdir_utf8);
+             tem = build_string (newdir_utf8);
+           }
+         else
+#else
+           tem = build_string (newdir);
+#endif
          if (multibyte && !STRING_MULTIBYTE (tem))
            {
              hdir = DECODE_FILE (tem);
@@ -1286,6 +1298,11 @@
             indirectly by prepending newdir to nm if necessary, and using
             cwd (or the wd of newdir's drive) as the new newdir.  */
          char *adir;
+#ifdef WINDOWSNT
+         const int adir_size = MAX_UTF8_PATH;
+#else
+         const int adir_size = MAXPATHLEN + 1;
+#endif
 
          if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
            {
@@ -1301,14 +1318,14 @@
              strcat (tmp, nm);
              nm = tmp;
            }
-         adir = alloca (MAXPATHLEN + 1);
+         adir = alloca (adir_size);
          if (drive)
            {
              if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
                strcpy (adir, "/");
            }
          else
-           getcwd (adir, MAXPATHLEN + 1);
+           getcwd (adir, adir_size);
          if (multibyte)
            {
              Lisp_Object tem = build_string (adir);
@@ -1479,7 +1496,7 @@
        target[1] = ':';
       }
     result = make_specified_string (target, -1, o - target, multibyte);
-    dostounix_filename (SSDATA (result), multibyte);
+    dostounix_filename (SSDATA (result));
 #ifdef WINDOWSNT
     if (!NILP (Vw32_downcase_file_names))
       result = Fdowncase (result);
@@ -1763,7 +1780,7 @@
   nm = xlispstrdupa (filename);
 
 #ifdef DOS_NT
-  dostounix_filename (nm, multibyte);
+  dostounix_filename (nm);
   substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
 #endif
   endp = nm + SBYTES (filename);
@@ -2661,9 +2678,9 @@
   if (!buf)
     return Qnil;
 
-  val = build_string (buf);
+  val = build_unibyte_string (buf);
   if (buf[0] == '/' && strchr (buf, ':'))
-    val = concat2 (build_string ("/:"), val);
+    val = concat2 (build_unibyte_string ("/:"), val);
   if (buf != readlink_buf)
     xfree (buf);
   val = DECODE_FILE (val);
@@ -5858,7 +5875,11 @@
 
   DEFVAR_LISP ("file-name-coding-system", Vfile_name_coding_system,
               doc: /* Coding system for encoding file names.
-If it is nil, `default-file-name-coding-system' (which see) is used.  */);
+If it is nil, `default-file-name-coding-system' (which see) is used.
+
+On MS-Windows, the value of this variable is largely ignored if
+\`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
+behaves as if file names were encoded in `utf-8'.  */);
   Vfile_name_coding_system = Qnil;
 
   DEFVAR_LISP ("default-file-name-coding-system",
@@ -5869,7 +5890,11 @@
 This variable is set/changed by the command `set-language-environment'.
 User should not set this variable manually,
 instead use `file-name-coding-system' to get a constant encoding
-of file names regardless of the current language environment.  */);
+of file names regardless of the current language environment.
+
+On MS-Windows, the value of this variable is largely ignored if
+\`w32-unicode-filenames' (which see) is non-nil.  Emacs on Windows
+behaves as if file names were encoded in `utf-8'.  */);
   Vdefault_file_name_coding_system = Qnil;
 
   DEFSYM (Qformat_decode, "format-decode");

=== modified file 'src/filelock.c'
--- a/src/filelock.c    2013-09-23 07:12:01 +0000
+++ b/src/filelock.c    2013-11-02 13:03:32 +0000
@@ -689,7 +689,7 @@
   /* Ensure we have only '/' separators, to avoid problems with
      looking (inside fill_in_lock_file_name) for backslashes in file
      names encoded by some DBCS codepage.  */
-  dostounix_filename (SSDATA (fn), 1);
+  dostounix_filename (SSDATA (fn));
 #endif
   encoded_fn = ENCODE_FILE (fn);
 

=== modified file 'src/gnutls.c'
--- a/src/gnutls.c      2013-11-30 13:31:39 +0000
+++ b/src/gnutls.c      2013-12-07 17:21:57 +0000
@@ -21,6 +21,7 @@
 
 #include "lisp.h"
 #include "process.h"
+#include "coding.h"
 
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
@@ -899,6 +900,13 @@
            {
              GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
                           SSDATA (trustfile));
+             trustfile = ENCODE_FILE (trustfile);
+#ifdef WINDOWSNT
+             /* Since GnuTLS doesn't support UTF-8 or UTF-16 encoded
+                file names on Windows, we need to re-encode the file
+                name using the current ANSI codepage.  */
+             trustfile = ansi_encode_filename (trustfile);
+#endif
              ret = fn_gnutls_certificate_set_x509_trust_file
                (x509_cred,
                 SSDATA (trustfile),
@@ -921,6 +929,10 @@
            {
              GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
                           SSDATA (crlfile));
+             crlfile = ENCODE_FILE (crlfile);
+#ifdef WINDOWSNT
+             crlfile = ansi_encode_filename (crlfile);
+#endif
              ret = fn_gnutls_certificate_set_x509_crl_file
                (x509_cred, SSDATA (crlfile), file_format);
 
@@ -944,6 +956,12 @@
                           SSDATA (keyfile));
              GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
                           SSDATA (certfile));
+             keyfile = ENCODE_FILE (keyfile);
+             certfile = ENCODE_FILE (certfile);
+#ifdef WINDOWSNT
+             keyfile = ansi_encode_filename (keyfile);
+             certfile = ansi_encode_filename (certfile);
+#endif
              ret = fn_gnutls_certificate_set_x509_key_file
                (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format);
 

=== modified file 'src/image.c'
--- a/src/image.c       2013-12-01 14:34:05 +0000
+++ b/src/image.c       2013-12-07 17:21:57 +0000
@@ -3590,6 +3590,12 @@
        }
 
 #ifdef HAVE_NTGUI
+#ifdef WINDOWSNT
+      /* FILE is encoded in UTF-8, but image libraries on Windows
+        support neither UTF-8 nor UTF-16 encoded file names.  So we
+        need to re-encode it in ANSI.  */
+      file = ansi_encode_filename (file);
+#endif
       /* XpmReadFileToPixmap is not available in the Windows port of
         libxpm.  But XpmReadFileToImage almost does what we want.  */
       rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
@@ -6968,6 +6974,9 @@
          image_error ("Cannot find image file `%s'", specified_file, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
 
       /* Try to open the image file.  */
       tiff = fn_TIFFOpen (SSDATA (file), "r");
@@ -7353,6 +7362,9 @@
          image_error ("Cannot find image file `%s'", specified_file, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
 
       /* Open the GIF file.  */
 #if GIFLIB_MAJOR < 5
@@ -8479,6 +8491,9 @@
          image_error ("Cannot find image file `%s'", file_name, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
       success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
     }
   /* Else its not a file, its a lisp object.  Load the image from a

=== modified file 'src/msdos.c'
--- a/src/msdos.c       2013-11-04 06:09:03 +0000
+++ b/src/msdos.c       2013-11-18 16:45:48 +0000
@@ -3295,7 +3295,7 @@
 /* Destructively turn backslashes into slashes.  */
 
 void
-dostounix_filename (char *p, int ignore)
+dostounix_filename (char *p)
 {
   msdos_downcase_filename (p);
 
@@ -3559,7 +3559,7 @@
   if (!s) s = "c:/command.com";
   t = alloca (strlen (s) + 1);
   strcpy (t, s);
-  dostounix_filename (t, 0);
+  dostounix_filename (t);
   setenv ("SHELL", t, 0);
 
   /* PATH is also downcased and backslashes mirrored.  */
@@ -3569,7 +3569,7 @@
   /* Current directory is always considered part of MsDos's path but it is
      not normally mentioned.  Now it is.  */
   strcat (strcpy (t, ".;"), s);
-  dostounix_filename (t, 0); /* Not a single file name, but this should work.  
*/
+  dostounix_filename (t); /* Not a single file name, but this should work.  */
   setenv ("PATH", t, 1);
 
   /* In some sense all dos users have root privileges, so...  */

=== modified file 'src/msdos.h'
--- a/src/msdos.h       2013-09-13 15:03:51 +0000
+++ b/src/msdos.h       2013-11-02 13:03:32 +0000
@@ -29,7 +29,7 @@
 
 int getdefdir (int, char*);
 void unixtodos_filename (char *);
-void dostounix_filename (char *, int);
+void dostounix_filename (char *);
 char *rootrelativepath (char *);
 void init_environment (int, char **, int);
 void internal_terminal_init (void);

=== modified file 'src/sysdep.c'
--- a/src/sysdep.c      2013-10-07 08:05:00 +0000
+++ b/src/sysdep.c      2013-10-26 12:14:33 +0000
@@ -464,7 +464,11 @@
 {
 #ifdef DOS_NT  /* Demacs 1.1.2 91/10/20 Manabu Higashida */
   int st;
+#ifdef MSDOS
   char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS.  */
+#else
+  char oldwd[MAX_UTF8_PATH];
+#endif
 #endif
   pid_t pid;
   int status;

=== modified file 'src/termcap.c'
--- a/src/termcap.c     2013-08-11 01:30:20 +0000
+++ b/src/termcap.c     2013-11-02 13:03:32 +0000
@@ -393,7 +393,7 @@
   if (termcap_name && (*termcap_name == '\\'
                       || *termcap_name == '/'
                       || termcap_name[1] == ':'))
-    dostounix_filename (termcap_name, 0);
+    dostounix_filename (termcap_name);
 #endif
 
   filep = termcap_name && valid_filename_p (termcap_name);

=== modified file 'src/unexw32.c'
--- a/src/unexw32.c     2013-04-16 18:08:03 +0000
+++ b/src/unexw32.c     2013-12-06 15:55:08 +0000
@@ -120,6 +120,8 @@
 
 /* File handling.  */
 
+/* Implementation note: this and the next functions work with ANSI
+   codepage encoded file names!  */
 int
 open_input_file (file_data *p_file, char *filename)
 {
@@ -128,8 +130,8 @@
   void  *file_base;
   unsigned long size, upper_size;
 
-  file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
-                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+  file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
   if (file == INVALID_HANDLE_VALUE)
     return FALSE;
 
@@ -166,9 +168,9 @@
      creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
      links to the same file, which defeats the purpose of these hard
      links: being able to run previous builds.  */
-  DeleteFile (filename);
-  file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
-                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+  DeleteFileA (filename);
+  file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
   if (file == INVALID_HANDLE_VALUE)
     return FALSE;
 
@@ -722,23 +724,30 @@
 unexec (const char *new_name, const char *old_name)
 {
   file_data in_file, out_file;
-  char out_filename[MAX_PATH], in_filename[MAX_PATH];
+  char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
   unsigned long size;
   char *p;
   char *q;
 
   /* Ignore old_name, and get our actual location from the OS.  */
-  if (!GetModuleFileName (NULL, in_filename, MAX_PATH))
+  if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
     abort ();
-  dostounix_filename (in_filename, 0);
+
+  /* Can't use dostounix_filename here, since that needs its file name
+     argument encoded in UTF-8.  */
+  for (p = in_filename; *p; p = CharNextA (p))
+    if (*p == '\\')
+      *p = '/';
+
   strcpy (out_filename, in_filename);
+  filename_to_ansi (new_name, new_name_a);
 
   /* Change the base of the output filename to match the requested name.  */
   if ((p = strrchr (out_filename, '/')) == NULL)
     abort ();
   /* The filenames have already been expanded, and will be in Unix
      format, so it is safe to expect an absolute name.  */
-  if ((q = strrchr (new_name, '/')) == NULL)
+  if ((q = strrchr (new_name_a, '/')) == NULL)
     abort ();
   strcpy (p, q);
 

=== modified file 'src/w32.c'
--- a/src/w32.c 2013-11-04 06:09:03 +0000
+++ b/src/w32.c 2013-12-09 20:21:58 +0000
@@ -248,7 +248,7 @@
 static int restore_privilege (TOKEN_PRIVILEGES *);
 static BOOL WINAPI revert_to_self (void);
 
-extern int sys_access (const char *, int);
+static int sys_access (const char *, int);
 extern void *e_malloc (size_t);
 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
                       struct timespec *, void *);
@@ -273,7 +273,8 @@
 static BOOL g_b_init_get_sid_sub_authority;
 static BOOL g_b_init_get_sid_sub_authority_count;
 static BOOL g_b_init_get_security_info;
-static BOOL g_b_init_get_file_security;
+static BOOL g_b_init_get_file_security_w;
+static BOOL g_b_init_get_file_security_a;
 static BOOL g_b_init_get_security_descriptor_owner;
 static BOOL g_b_init_get_security_descriptor_group;
 static BOOL g_b_init_is_valid_sid;
@@ -292,12 +293,14 @@
 static BOOL g_b_init_copy_sid;
 static BOOL g_b_init_get_native_system_info;
 static BOOL g_b_init_get_system_times;
-static BOOL g_b_init_create_symbolic_link;
+static BOOL g_b_init_create_symbolic_link_w;
+static BOOL g_b_init_create_symbolic_link_a;
 static BOOL g_b_init_get_security_descriptor_dacl;
 static BOOL g_b_init_convert_sd_to_sddl;
 static BOOL g_b_init_convert_sddl_to_sd;
 static BOOL g_b_init_is_valid_security_descriptor;
-static BOOL g_b_init_set_file_security;
+static BOOL g_b_init_set_file_security_w;
+static BOOL g_b_init_set_file_security_a;
 static BOOL g_b_init_get_adapters_info;
 
 /*
@@ -327,12 +330,8 @@
 
 #ifdef _UNICODE
 const char * const LookupAccountSid_Name = "LookupAccountSidW";
-const char * const GetFileSecurity_Name =  "GetFileSecurityW";
-const char * const SetFileSecurity_Name =  "SetFileSecurityW";
 #else
 const char * const LookupAccountSid_Name = "LookupAccountSidA";
-const char * const GetFileSecurity_Name =  "GetFileSecurityA";
-const char * const SetFileSecurity_Name =  "SetFileSecurityA";
 #endif
 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
     LPCTSTR lpSystemName,
@@ -356,14 +355,24 @@
     PACL *ppDacl,
     PACL *ppSacl,
     PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
-typedef BOOL (WINAPI * GetFileSecurity_Proc) (
-    LPCTSTR lpFileName,
-    SECURITY_INFORMATION RequestedInformation,
-    PSECURITY_DESCRIPTOR pSecurityDescriptor,
-    DWORD nLength,
-    LPDWORD lpnLengthNeeded);
-typedef BOOL (WINAPI *SetFileSecurity_Proc) (
-    LPCTSTR lpFileName,
+typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
+    LPCWSTR lpFileName,
+    SECURITY_INFORMATION RequestedInformation,
+    PSECURITY_DESCRIPTOR pSecurityDescriptor,
+    DWORD nLength,
+    LPDWORD lpnLengthNeeded);
+typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
+    LPCSTR lpFileName,
+    SECURITY_INFORMATION RequestedInformation,
+    PSECURITY_DESCRIPTOR pSecurityDescriptor,
+    DWORD nLength,
+    LPDWORD lpnLengthNeeded);
+typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
+    LPCWSTR lpFileName,
+    SECURITY_INFORMATION SecurityInformation,
+    PSECURITY_DESCRIPTOR pSecurityDescriptor);
+typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
+    LPCSTR lpFileName,
     SECURITY_INFORMATION SecurityInformation,
     PSECURITY_DESCRIPTOR pSecurityDescriptor);
 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
@@ -425,9 +434,13 @@
     LPFILETIME lpIdleTime,
     LPFILETIME lpKernelTime,
     LPFILETIME lpUserTime);
-typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
-    LPTSTR lpSymlinkFileName,
-    LPTSTR lpTargetFileName,
+typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
+    LPCWSTR lpSymlinkFileName,
+    LPCWSTR lpTargetFileName,
+    DWORD  dwFlags);
+typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
+    LPCSTR lpSymlinkFileName,
+    LPCSTR lpTargetFileName,
     DWORD  dwFlags);
 typedef BOOL (WINAPI 
*ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
     LPCTSTR StringSecurityDescriptor,
@@ -679,64 +692,121 @@
 }
 
 static BOOL WINAPI
-get_file_security (LPCTSTR lpFileName,
+get_file_security (const char *lpFileName,
                   SECURITY_INFORMATION RequestedInformation,
                   PSECURITY_DESCRIPTOR pSecurityDescriptor,
                   DWORD nLength,
                   LPDWORD lpnLengthNeeded)
 {
-  static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
+  static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
+  static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       errno = ENOTSUP;
       return FALSE;
     }
-  if (g_b_init_get_file_security == 0)
-    {
-      g_b_init_get_file_security = 1;
-      hm_advapi32 = LoadLibrary ("Advapi32.dll");
-      s_pfn_Get_File_Security =
-        (GetFileSecurity_Proc) GetProcAddress (
-            hm_advapi32, GetFileSecurity_Name);
-    }
-  if (s_pfn_Get_File_Security == NULL)
-    {
-      errno = ENOTSUP;
-      return FALSE;
-    }
-  return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
-                                  pSecurityDescriptor, nLength,
-                                  lpnLengthNeeded));
+  if (w32_unicode_filenames)
+    {
+      wchar_t filename_w[MAX_PATH];
+
+      if (g_b_init_get_file_security_w == 0)
+       {
+         g_b_init_get_file_security_w = 1;
+         hm_advapi32 = LoadLibrary ("Advapi32.dll");
+         s_pfn_Get_File_SecurityW =
+           (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
+                                                  "GetFileSecurityW");
+       }
+      if (s_pfn_Get_File_SecurityW == NULL)
+       {
+         errno = ENOTSUP;
+         return FALSE;
+       }
+      filename_to_utf16 (lpFileName, filename_w);
+      return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
+                                       pSecurityDescriptor, nLength,
+                                       lpnLengthNeeded));
+    }
+  else
+    {
+      char filename_a[MAX_PATH];
+
+      if (g_b_init_get_file_security_a == 0)
+       {
+         g_b_init_get_file_security_a = 1;
+         hm_advapi32 = LoadLibrary ("Advapi32.dll");
+         s_pfn_Get_File_SecurityA =
+           (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
+                                                  "GetFileSecurityA");
+       }
+      if (s_pfn_Get_File_SecurityA == NULL)
+       {
+         errno = ENOTSUP;
+         return FALSE;
+       }
+      filename_to_ansi (lpFileName, filename_a);
+      return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
+                                       pSecurityDescriptor, nLength,
+                                       lpnLengthNeeded));
+    }
 }
 
 static BOOL WINAPI
-set_file_security (LPCTSTR lpFileName,
+set_file_security (const char *lpFileName,
                   SECURITY_INFORMATION SecurityInformation,
                   PSECURITY_DESCRIPTOR pSecurityDescriptor)
 {
-  static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
+  static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
+  static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
   HMODULE hm_advapi32 = NULL;
   if (is_windows_9x () == TRUE)
     {
       errno = ENOTSUP;
       return FALSE;
     }
-  if (g_b_init_set_file_security == 0)
-    {
-      g_b_init_set_file_security = 1;
-      hm_advapi32 = LoadLibrary ("Advapi32.dll");
-      s_pfn_Set_File_Security =
-        (SetFileSecurity_Proc) GetProcAddress (
-            hm_advapi32, SetFileSecurity_Name);
-    }
-  if (s_pfn_Set_File_Security == NULL)
-    {
-      errno = ENOTSUP;
-      return FALSE;
-    }
-  return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
-                                  pSecurityDescriptor));
+  if (w32_unicode_filenames)
+    {
+      wchar_t filename_w[MAX_PATH];
+
+      if (g_b_init_set_file_security_w == 0)
+       {
+         g_b_init_set_file_security_w = 1;
+         hm_advapi32 = LoadLibrary ("Advapi32.dll");
+         s_pfn_Set_File_SecurityW =
+           (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
+                                                   "SetFileSecurityW");
+       }
+      if (s_pfn_Set_File_SecurityW == NULL)
+       {
+         errno = ENOTSUP;
+         return FALSE;
+       }
+      filename_to_utf16 (lpFileName, filename_w);
+      return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
+                                       pSecurityDescriptor));
+    }
+  else
+    {
+      char filename_a[MAX_PATH];
+
+      if (g_b_init_set_file_security_a == 0)
+       {
+         g_b_init_set_file_security_a = 1;
+         hm_advapi32 = LoadLibrary ("Advapi32.dll");
+         s_pfn_Set_File_SecurityA =
+           (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
+                                                   "SetFileSecurityA");
+       }
+      if (s_pfn_Set_File_SecurityA == NULL)
+       {
+         errno = ENOTSUP;
+         return FALSE;
+       }
+      filename_to_ansi (lpFileName, filename_a);
+      return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
+                                       pSecurityDescriptor));
+    }
 }
 
 static BOOL WINAPI
@@ -973,11 +1043,12 @@
 }
 
 static BOOLEAN WINAPI
-create_symbolic_link (LPTSTR lpSymlinkFilename,
-                     LPTSTR lpTargetFileName,
+create_symbolic_link (LPCSTR lpSymlinkFilename,
+                     LPCSTR lpTargetFileName,
                      DWORD dwFlags)
 {
-  static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
+  static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
+  static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
   BOOLEAN retval;
 
   if (is_windows_9x () == TRUE)
@@ -985,39 +1056,74 @@
       errno = ENOSYS;
       return 0;
     }
-  if (g_b_init_create_symbolic_link == 0)
-    {
-      g_b_init_create_symbolic_link = 1;
-#ifdef _UNICODE
-      s_pfn_Create_Symbolic_Link =
-       (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle 
("kernel32.dll"),
-                                                "CreateSymbolicLinkW");
-#else
-      s_pfn_Create_Symbolic_Link =
-       (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle 
("kernel32.dll"),
-                                                "CreateSymbolicLinkA");
-#endif
-    }
-  if (s_pfn_Create_Symbolic_Link == NULL)
-    {
-      errno = ENOSYS;
-      return 0;
-    }
-
-  retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
-                                      dwFlags);
-  /* If we were denied creation of the symlink, try again after
-     enabling the SeCreateSymbolicLinkPrivilege for our process.  */
-  if (!retval)
-    {
-      TOKEN_PRIVILEGES priv_current;
-
-      if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
-       {
-         retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, 
lpTargetFileName,
-                                              dwFlags);
-         restore_privilege (&priv_current);
-         revert_to_self ();
+  if (w32_unicode_filenames)
+    {
+      wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
+
+      if (g_b_init_create_symbolic_link_w == 0)
+       {
+         g_b_init_create_symbolic_link_w = 1;
+         s_pfn_Create_Symbolic_LinkW =
+           (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle 
("kernel32.dll"),
+                                                    "CreateSymbolicLinkW");
+       }
+      if (s_pfn_Create_Symbolic_LinkW == NULL)
+       {
+         errno = ENOSYS;
+         return 0;
+       }
+
+      filename_to_utf16 (lpSymlinkFilename, symfn_w);
+      filename_to_utf16 (lpTargetFileName, tgtfn_w);
+      retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
+      /* If we were denied creation of the symlink, try again after
+        enabling the SeCreateSymbolicLinkPrivilege for our process.  */
+      if (!retval)
+       {
+         TOKEN_PRIVILEGES priv_current;
+
+         if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
+                               &priv_current))
+           {
+             retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
+             restore_privilege (&priv_current);
+             revert_to_self ();
+           }
+       }
+    }
+  else
+    {
+      char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
+
+      if (g_b_init_create_symbolic_link_a == 0)
+       {
+         g_b_init_create_symbolic_link_a = 1;
+         s_pfn_Create_Symbolic_LinkA =
+           (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle 
("kernel32.dll"),
+                                                    "CreateSymbolicLinkA");
+       }
+      if (s_pfn_Create_Symbolic_LinkA == NULL)
+       {
+         errno = ENOSYS;
+         return 0;
+       }
+
+      filename_to_ansi (lpSymlinkFilename, symfn_a);
+      filename_to_ansi (lpTargetFileName, tgtfn_a);
+      retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
+      /* If we were denied creation of the symlink, try again after
+        enabling the SeCreateSymbolicLinkPrivilege for our process.  */
+      if (!retval)
+       {
+         TOKEN_PRIVILEGES priv_current;
+
+         if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
+                               &priv_current))
+           {
+             retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
+             restore_privilege (&priv_current);
+             revert_to_self ();
+           }
        }
     }
   return retval;
@@ -1182,7 +1288,297 @@
     return -1;
 }
 
-static char startup_dir[MAXPATHLEN];
+
+
+/* Here's an overview of how the Windows build supports file names
+   that cannot be encoded by the current system codepage.
+
+   From the POV of Lisp and layers of C code above the functions here,
+   Emacs on Windows pretends that its file names are encoded in UTF-8;
+   see encode_file and decode_file on coding.c.  Any file name that is
+   passed as a unibyte string to C functions defined here is assumed
+   to be in UTF-8 encoding.  Any file name returned by functions
+   defined here must be in UTF-8 encoding, with only a few exceptions
+   reserved for a couple of special cases.  (Be sure to use
+   MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
+   as they can be much longer than MAX_PATH!)
+
+   The UTF-8 encoded file names cannot be passed to system APIs, as
+   Windows does not support that.  Therefore, they are converted
+   either to UTF-16 or to the ANSI codepage, depending on the value of
+   w32-unicode-filenames, before calling any system APIs or CRT library
+   functions.  The default value of that variable is determined by the
+   OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
+   user can change that default (although I don't see why would she
+   want to).
+
+   The 4 functions defined below, filename_to_utf16, filename_to_ansi,
+   filename_from_utf16, and filename_from_ansi, are the workhorses of
+   these conversions.  They rely on Windows native APIs
+   MultiByteToWideChar and WideCharToMultiByte; we cannot use
+   functions from coding.c here, because they allocate memory, which
+   is a bad idea on the level of libc, which is what the functions
+   here emulate.  (If you worry about performance due to constant
+   conversion back and forth from UTF-8 to UTF-16, then don't: first,
+   it was measured to take only a few microseconds on a not-so-fast
+   machine, and second, that's exactly what the ANSI APIs we used
+   before do anyway, because they are just thin wrappers around the
+   Unicode APIs.)
+
+   The variables file-name-coding-system and default-file-name-coding-system
+   still exist, but are actually used only when a file name needs to
+   be converted to the ANSI codepage.  This happens all the time when
+   w32-unicode-filenames is nil, but can also happen from time to time
+   when it is t.  Otherwise, these variables have no effect on file-name
+   encoding when w32-unicode-filenames is t; this is similar to
+   selection-coding-system.
+
+   This arrangement works very well, but it has a few gotchas and
+   limitations:
+
+   . Lisp code that encodes or decodes file names manually should
+     normally use 'utf-8' as the coding-system on Windows,
+     disregarding file-name-coding-system.  This is a somewhat
+     unpleasant consequence, but it cannot be avoided.  Fortunately,
+     very few Lisp packages need to do that.
+
+     More generally, passing to library functions (e.g., fopen or
+     opendir) file names already encoded in the ANSI codepage is
+     explictly *verboten*, as all those functions, as shadowed and
+     emulated here, assume they will receive UTF-8 encoded file names.
+
+     For the same reasons, no CRT function or Win32 API can be called
+     directly in Emacs sources, without either converting the file
+     name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
+     through some shadowing function defined here.
+
+   . Environment variables stored in Vprocess_environment are encoded
+     in the ANSI codepage, so if getenv/egetenv is used for a variable
+     whose value is a file name or a list of directories, it needs to
+     be converted to UTF-8, before it is used as argument to functions
+     or decoded into a Lisp string.
+
+   . File names passed to external libraries, like the image libraries
+     and GnuTLS, need special handling.  These libraries generally
+     don't support UTF-16 or UTF-8 file names, so they must get file
+     names encoded in the ANSI codepage.  To facilitate using these
+     libraries with file names that are not encodable in the ANSI
+     codepage, use the function ansi_encode_filename, which will try
+     to use the short 8+3 alias of a file name if that file name is
+     not encodable in the ANSI codepage.  See image.c and gnutls.c for
+     examples of how this should be done.
+
+   . Running subprocesses in non-ASCII directories and with non-ASCII
+     file arguments is limited to the current codepage (even though
+     Emacs is perfectly capable of finding an executable program file
+     even in a directory whose name cannot be encoded in the curreent
+     codepage).  This is because the command-line arguments are
+     encoded _before_ they get to the w32-specific level, and the
+     encoding is not known in advance (it doesn't have to be the
+     current ANSI codepage), so w32proc.c functions cannot re-encode
+     them in UTF-16.  This should be fixed, but will also require
+     changes in cmdproxy.  The current limitation is not terribly bad
+     anyway, since very few, if any, Windows console programs that are
+     likely to be invoked by Emacs support UTF-16 encoded command
+     lines.
+
+   . For similar reasons, server.el and emacsclient are also limited
+     to the current ANSI codepage for now.
+
+   . Emacs itself can only handle command-line arguments encoded in
+     the current codepage.
+
+   . Turning on w32-unicode-filename on Windows 9X (if it at all
+     works) requires UNICOWS.DLL, which is currently loaded only in a
+     GUI session.  */
+
+
+
+/* Converting file names from UTF-8 to either UTF-16 or the ANSI
+   codepage defined by file-name-coding-system.  */
+
+/* Current codepage for encoding file names.  */
+static int file_name_codepage;
+
+/* Produce a Windows ANSI codepage suitable for encoding file names.
+   Return the information about that codepage in CP_INFO.  */
+static int
+codepage_for_filenames (CPINFO *cp_info)
+{
+  /* A simple cache to avoid calling GetCPInfo every time we need to
+     encode/decode a file name.  The file-name encoding is not
+     supposed to be changed too frequently, if ever.  */
+  static Lisp_Object last_file_name_encoding;
+  static CPINFO cp;
+  Lisp_Object current_encoding;
+
+  current_encoding = Vfile_name_coding_system;
+  if (NILP (current_encoding))
+    current_encoding = Vdefault_file_name_coding_system;
+
+  if (!EQ (last_file_name_encoding, current_encoding))
+    {
+      /* Default to the current ANSI codepage.  */
+      file_name_codepage = w32_ansi_code_page;
+
+      if (NILP (current_encoding))
+       {
+         char *cpname = SDATA (SYMBOL_NAME (current_encoding));
+         char *cp = NULL, *end;
+         int cpnum;
+
+         if (strncmp (cpname, "cp", 2) == 0)
+           cp = cpname + 2;
+         else if (strncmp (cpname, "windows-", 8) == 0)
+           cp = cpname + 8;
+
+         if (cp)
+           {
+             end = cp;
+             cpnum = strtol (cp, &end, 10);
+             if (cpnum && *end == '\0' && end - cp >= 2)
+               file_name_codepage = cpnum;
+           }
+       }
+
+      if (!file_name_codepage)
+       file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
+
+      if (!GetCPInfo (file_name_codepage, &cp))
+       {
+         file_name_codepage = CP_ACP;
+         if (!GetCPInfo (file_name_codepage, &cp))
+           emacs_abort ();
+       }
+    }
+  if (cp_info)
+    *cp_info = cp;
+
+  return file_name_codepage;
+}
+
+int
+filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
+{
+  int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
+                                   fn_out, MAX_PATH);
+
+  if (!result)
+    {
+      DWORD err = GetLastError ();
+
+      switch (err)
+       {
+       case ERROR_INVALID_FLAGS:
+       case ERROR_INVALID_PARAMETER:
+         errno = EINVAL;
+         break;
+       case ERROR_INSUFFICIENT_BUFFER:
+       case ERROR_NO_UNICODE_TRANSLATION:
+       default:
+         errno = ENOENT;
+         break;
+       }
+      return -1;
+    }
+  return 0;
+}
+
+int
+filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
+{
+  int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
+                                   fn_out, MAX_UTF8_PATH, NULL, NULL);
+
+  if (!result)
+    {
+      DWORD err = GetLastError ();
+
+      switch (err)
+       {
+       case ERROR_INVALID_FLAGS:
+       case ERROR_INVALID_PARAMETER:
+         errno = EINVAL;
+         break;
+       case ERROR_INSUFFICIENT_BUFFER:
+       case ERROR_NO_UNICODE_TRANSLATION:
+       default:
+         errno = ENOENT;
+         break;
+       }
+      return -1;
+    }
+  return 0;
+}
+
+int
+filename_to_ansi (const char *fn_in, char *fn_out)
+{
+  wchar_t fn_utf16[MAX_PATH];
+
+  if (filename_to_utf16 (fn_in, fn_utf16) == 0)
+    {
+      int result;
+      int codepage = codepage_for_filenames (NULL);
+
+      result  = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
+                                    fn_out, MAX_PATH, NULL, NULL);
+      if (!result)
+       {
+         DWORD err = GetLastError ();
+
+         switch (err)
+           {
+           case ERROR_INVALID_FLAGS:
+           case ERROR_INVALID_PARAMETER:
+             errno = EINVAL;
+             break;
+           case ERROR_INSUFFICIENT_BUFFER:
+           case ERROR_NO_UNICODE_TRANSLATION:
+           default:
+             errno = ENOENT;
+             break;
+           }
+         return -1;
+       }
+      return 0;
+    }
+  return -1;
+}
+
+int
+filename_from_ansi (const char *fn_in, char *fn_out)
+{
+  wchar_t fn_utf16[MAX_PATH];
+  int codepage = codepage_for_filenames (NULL);
+  int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
+                                   fn_utf16, MAX_PATH);
+
+  if (!result)
+    {
+      DWORD err = GetLastError ();
+
+      switch (err)
+       {
+       case ERROR_INVALID_FLAGS:
+       case ERROR_INVALID_PARAMETER:
+         errno = EINVAL;
+         break;
+       case ERROR_INSUFFICIENT_BUFFER:
+       case ERROR_NO_UNICODE_TRANSLATION:
+       default:
+         errno = ENOENT;
+         break;
+       }
+      return -1;
+    }
+  return filename_from_utf16 (fn_utf16, fn_out);
+}
+
+
+
+/* The directory where we started, in UTF-8. */
+static char startup_dir[MAX_UTF8_PATH];
 
 /* Get the current working directory.  */
 char *
@@ -1374,8 +1770,8 @@
 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
-static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
-static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
+static char dflt_passwd_dir[MAX_UTF8_PATH];
+static char dflt_passwd_shell[MAX_UTF8_PATH];
 
 static struct passwd dflt_passwd =
 {
@@ -1556,15 +1952,32 @@
     }
   dflt_group.gr_gid = dflt_passwd.pw_gid;
 
-  /* Ensure HOME and SHELL are defined. */
-  if (getenv ("HOME") == NULL)
-    emacs_abort ();
-  if (getenv ("SHELL") == NULL)
-    emacs_abort ();
-
   /* Set dir and shell from environment variables. */
-  strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
-  strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
+  if (w32_unicode_filenames)
+    {
+      wchar_t *home = _wgetenv (L"HOME");
+      wchar_t *shell = _wgetenv (L"SHELL");
+
+      /* Ensure HOME and SHELL are defined. */
+      if (home == NULL)
+       emacs_abort ();
+      if (shell == NULL)
+       emacs_abort ();
+      filename_from_utf16 (home, dflt_passwd.pw_dir);
+      filename_from_utf16 (shell, dflt_passwd.pw_shell);
+    }
+  else
+    {
+      char *home = getenv ("HOME");
+      char *shell = getenv ("SHELL");
+
+      if (home == NULL)
+       emacs_abort ();
+      if (shell == NULL)
+       emacs_abort ();
+      filename_from_ansi (home, dflt_passwd.pw_dir);
+      filename_from_ansi (shell, dflt_passwd.pw_shell);
+    }
 
   xfree (buf);
   if (token)
@@ -1584,93 +1997,32 @@
   srand (seed);
 }
 
-/* Current codepage for encoding file names.  */
-static int file_name_codepage;
-
 /* Return the maximum length in bytes of a multibyte character
    sequence encoded in the current ANSI codepage.  This is required to
    correctly walk the encoded file names one character at a time.  */
 static int
 max_filename_mbslen (void)
 {
-  /* A simple cache to avoid calling GetCPInfo every time we need to
-     normalize a file name.  The file-name encoding is not supposed to
-     be changed too frequently, if ever.  */
-  static Lisp_Object last_file_name_encoding;
-  static int last_max_mbslen;
-  Lisp_Object current_encoding;
-
-  current_encoding = Vfile_name_coding_system;
-  if (NILP (current_encoding))
-    current_encoding = Vdefault_file_name_coding_system;
-
-  if (!EQ (last_file_name_encoding, current_encoding))
-    {
-      CPINFO cp_info;
-
-      last_file_name_encoding = current_encoding;
-      /* Default to the current ANSI codepage.  */
-      file_name_codepage = w32_ansi_code_page;
-      if (!NILP (current_encoding))
-       {
-         char *cpname = SDATA (SYMBOL_NAME (current_encoding));
-         char *cp = NULL, *end;
-         int cpnum;
-
-         if (strncmp (cpname, "cp", 2) == 0)
-           cp = cpname + 2;
-         else if (strncmp (cpname, "windows-", 8) == 0)
-           cp = cpname + 8;
-
-         if (cp)
-           {
-             end = cp;
-             cpnum = strtol (cp, &end, 10);
-             if (cpnum && *end == '\0' && end - cp >= 2)
-               file_name_codepage = cpnum;
-           }
-       }
-
-      if (!file_name_codepage)
-       file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
-
-      if (!GetCPInfo (file_name_codepage, &cp_info))
-       {
-         file_name_codepage = CP_ACP;
-         if (!GetCPInfo (file_name_codepage, &cp_info))
-           emacs_abort ();
-       }
-      last_max_mbslen = cp_info.MaxCharSize;
-    }
-
-  return last_max_mbslen;
+  CPINFO cp_info;
+
+  codepage_for_filenames (&cp_info);
+  return cp_info.MaxCharSize;
 }
 
-/* Normalize filename by converting all path separators to
-   the specified separator.  Also conditionally convert upper
-   case path name components to lower case.  */
+/* Normalize filename by converting in-place all of its path
+   separators to the separator specified by PATH_SEP.  */
 
 static void
-normalize_filename (register char *fp, char path_sep, int multibyte)
+normalize_filename (register char *fp, char path_sep)
 {
-  char sep;
-  char *elem, *p2;
-  int dbcs_p = max_filename_mbslen () > 1;
-
-  /* Multibyte file names are in the Emacs internal representation, so
-     we can traverse them by bytes with no problems.  */
-  if (multibyte)
-    dbcs_p = 0;
+  char *p2;
 
   /* Always lower-case drive letters a-z, even if the filesystem
      preserves case in filenames.
      This is so filenames can be compared by string comparison
      functions that are case-sensitive.  Even case-preserving filesystems
      do not distinguish case in drive letters.  */
-  if (dbcs_p)
-    p2 = CharNextExA (file_name_codepage, fp, 0);
-  else
-    p2 = fp + 1;
+  p2 = fp + 1;
 
   if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
     {
@@ -1678,68 +2030,26 @@
       fp += 2;
     }
 
-  if (multibyte || NILP (Vw32_downcase_file_names))
+  while (*fp)
     {
-      while (*fp)
-       {
-         if (*fp == '/' || *fp == '\\')
-           *fp = path_sep;
-         if (!dbcs_p)
-           fp++;
-         else
-           fp = CharNextExA (file_name_codepage, fp, 0);
-       }
-      return;
+      if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
+       *fp = path_sep;
+      fp++;
     }
-
-  sep = path_sep;              /* convert to this path separator */
-  elem = fp;                   /* start of current path element */
-
-  do {
-    if (*fp >= 'a' && *fp <= 'z')
-      elem = 0;                        /* don't convert this element */
-
-    if (*fp == 0 || *fp == ':')
-      {
-       sep = *fp;              /* restore current separator (or 0) */
-       *fp = '/';              /* after conversion of this element */
-      }
-
-    if (*fp == '/' || *fp == '\\')
-      {
-       if (elem && elem != fp)
-         {
-           *fp = 0;            /* temporary end of string */
-           _mbslwr (elem);     /* while we convert to lower case */
-         }
-       *fp = sep;              /* convert (or restore) path separator */
-       elem = fp + 1;          /* next element starts after separator */
-       sep = path_sep;
-      }
-    if (*fp)
-      {
-       if (!dbcs_p)
-         fp++;
-       else
-         fp = CharNextExA (file_name_codepage, fp, 0);
-      }
-  } while (*fp);
 }
 
-/* Destructively turn backslashes into slashes.  MULTIBYTE non-zero
-   means the file name is a multibyte string in Emacs's internal
-   representation.  */
+/* Destructively turn backslashes into slashes.  */
 void
-dostounix_filename (register char *p, int multibyte)
+dostounix_filename (register char *p)
 {
-  normalize_filename (p, '/', multibyte);
+  normalize_filename (p, '/');
 }
 
 /* Destructively turn slashes into backslashes.  */
 void
 unixtodos_filename (register char *p)
 {
-  normalize_filename (p, '\\', 0);
+  normalize_filename (p, '\\');
 }
 
 /* Remove all CR's that are followed by a LF.
@@ -1772,9 +2082,9 @@
 /* Parse the root part of file name, if present.  Return length and
     optionally store pointer to char after root.  */
 static int
-parse_root (char * name, char ** pPath)
+parse_root (const char * name, const char ** pPath)
 {
-  char * start = name;
+  const char * start = name;
 
   if (name == NULL)
     return 0;
@@ -1790,17 +2100,13 @@
   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
     {
       int slashes = 2;
-      int dbcs_p = max_filename_mbslen () > 1;
 
       name += 2;
       do
         {
          if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
            break;
-         if (dbcs_p)
-           name = CharNextExA (file_name_codepage, name, 0);
-         else
-           name++;
+         name++;
        }
       while ( *name );
       if (IS_DIRECTORY_SEP (name[0]))
@@ -1817,23 +2123,63 @@
 static int
 get_long_basename (char * name, char * buf, int size)
 {
-  WIN32_FIND_DATA find_data;
-  HANDLE dir_handle;
+  HANDLE dir_handle = INVALID_HANDLE_VALUE;
+  char fname_utf8[MAX_UTF8_PATH];
   int len = 0;
+  int cstatus = -1;
 
-  /* must be valid filename, no wild cards or other invalid characters */
-  if (_mbspbrk (name, "*?|<>\""))
+  /* Must be valid filename, no wild cards or other invalid characters.  */
+  if (strpbrk (name, "*?|<>\""))
     return 0;
 
-  dir_handle = FindFirstFile (name, &find_data);
+  if (w32_unicode_filenames)
+    {
+      wchar_t fname_utf16[MAX_PATH];
+      WIN32_FIND_DATAW find_data_wide;
+
+      filename_to_utf16 (name, fname_utf16);
+      dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
+      if (dir_handle != INVALID_HANDLE_VALUE)
+       cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
+    }
+  else
+    {
+      char fname_ansi[MAX_PATH];
+      WIN32_FIND_DATAA find_data_ansi;
+
+      filename_to_ansi (name, fname_ansi);
+      /* If the ANSI name includes ? characters, it is not encodable
+        in the ANSI codepage.  In that case, we deliver the question
+        marks to the caller; calling FindFirstFileA in this case
+        could return some unrelated file name in the same
+        directory.  */
+      if (_mbspbrk (fname_ansi, "?"))
+       {
+         /* Find the basename of fname_ansi.  */
+         char *p = strrchr (fname_ansi, '\\');
+
+         if (!p)
+           p = fname_ansi;
+         else
+           p++;
+         cstatus = filename_from_ansi (p, fname_utf8);
+       }
+      else
+       {
+         dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
+         if (dir_handle != INVALID_HANDLE_VALUE)
+           cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
+       }
+    }
+
+  if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
+    memcpy (buf, fname_utf8, len + 1);
+  else
+    len = 0;
+
   if (dir_handle != INVALID_HANDLE_VALUE)
-    {
-      if ((len = strlen (find_data.cFileName)) < size)
-       memcpy (buf, find_data.cFileName, len + 1);
-      else
-       len = 0;
-      FindClose (dir_handle);
-    }
+    FindClose (dir_handle);
+
   return len;
 }
 
@@ -1843,12 +2189,12 @@
 {
   char * o = buf;
   char * p;
-  char * q;
-  char full[ MAX_PATH ];
+  const char * q;
+  char full[ MAX_UTF8_PATH ];
   int len;
 
   len = strlen (name);
-  if (len >= MAX_PATH)
+  if (len >= MAX_UTF8_PATH)
     return FALSE;
 
   /* Use local copy for destructive modification.  */
@@ -1856,7 +2202,7 @@
   unixtodos_filename (full);
 
   /* Copy root part verbatim.  */
-  len = parse_root (full, &p);
+  len = parse_root (full, (const char **)&p);
   memcpy (o, full, len);
   o += len;
   *o = '\0';
@@ -1865,7 +2211,7 @@
   while (p != NULL && *p)
     {
       q = p;
-      p = _mbschr (q, '\\');
+      p = strchr (q, '\\');
       if (p) *p = '\0';
       len = get_long_basename (full, o, size);
       if (len > 0)
@@ -1889,6 +2235,59 @@
   return TRUE;
 }
 
+unsigned int
+w32_get_short_filename (char * name, char * buf, int size)
+{
+  if (w32_unicode_filenames)
+    {
+      wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
+      unsigned int retval;
+
+      filename_to_utf16 (name, name_utf16);
+      retval = GetShortPathNameW (name_utf16, short_name, size);
+      if (retval && retval < size)
+       filename_from_utf16 (short_name, buf);
+      return retval;
+    }
+  else
+    {
+      char name_ansi[MAX_PATH];
+
+      filename_to_ansi (name, name_ansi);
+      return GetShortPathNameA (name_ansi, buf, size);
+    }
+}
+
+/* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
+   MS-Windows ANSI codepage.  If FILENAME includes characters not
+   supported by the ANSI codepage, return the 8+3 alias of FILENAME,
+   if it exists.  This is needed because the w32 build wants to
+   support file names outside of the system locale, but image
+   libraries typically don't support wide (a.k.a. "Unicode") APIs
+   required for that.  */
+
+Lisp_Object
+ansi_encode_filename (Lisp_Object filename)
+{
+  Lisp_Object encoded_filename;
+  char fname[MAX_PATH];
+
+  filename_to_ansi (SSDATA (filename), fname);
+  if (_mbspbrk (fname, "?"))
+    {
+      char shortname[MAX_PATH];
+
+      if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
+       {
+         dostounix_filename (shortname);
+         encoded_filename = build_string (shortname);
+       }
+    }
+  else
+    encoded_filename = build_unibyte_string (fname);
+  return encoded_filename;
+}
+
 static int
 is_unc_volume (const char *filename)
 {
@@ -1897,7 +2296,7 @@
   if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
     return 0;
 
-  if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
+  if (strpbrk (ptr + 2, "*?|<>\"\\/"))
     return 0;
 
   return 1;
@@ -1997,8 +2396,8 @@
   return (NULL);
 }
 
-char *get_emacs_configuration (void);
-
+/* The argv[] array holds ANSI-encoded strings, and so this function
+   works with ANS_encoded strings.  */
 void
 init_environment (char ** argv)
 {
@@ -2010,6 +2409,13 @@
 
   const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
 
+  /* Implementation note: This function explicitly works with ANSI
+     file names, not with UTF-8 encoded file names.  This is because
+     this function pushes variables into the Emacs's environment, and
+     the environment variables are always assumed to be in the
+     locale-specific encoding.  Do NOT call any functions that accept
+     UTF-8 file names from this function!  */
+
   /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
      temporary files and assume "/tmp" if $TMPDIR is unset, which
      will break on DOS/Windows.  Refuse to work if we cannot find
@@ -2025,8 +2431,8 @@
         The only way to be really sure is to actually create a file and
         see if it succeeds.  But I think that's too much to ask.  */
 
-      /* MSVCRT's _access crashes with D_OK.  */
-      if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
+      /* MSVCRT's _access crashes with D_OK, so we use our replacement.  */
+      if (tmp && sys_access (tmp, D_OK) == 0)
        {
          char * var = alloca (strlen (tmp) + 8);
          sprintf (var, "TMPDIR=%s", tmp);
@@ -2088,7 +2494,7 @@
     /* For backwards compatibility, check if a .emacs file exists in C:/
        If not, then we can try to default to the appdata directory under the
        user's profile, which is more likely to be writable.   */
-    if (faccessat (AT_FDCWD, "C:/.emacs", F_OK, AT_EACCESS) != 0)
+    if (sys_access ("C:/.emacs", F_OK) != 0)
       {
        HRESULT profile_result;
        /* Dynamically load ShGetFolderPath, as it won't exist on versions
@@ -2135,7 +2541,7 @@
       char *p;
       char modname[MAX_PATH];
 
-      if (!GetModuleFileName (NULL, modname, MAX_PATH))
+      if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
        emacs_abort ();
       if ((p = _mbsrchr (modname, '\\')) == NULL)
        emacs_abort ();
@@ -2164,33 +2570,6 @@
              _putenv (strdup (buf));
            }
        }
-      /* Handle running emacs from the build directory: src/oo-spd/i386/  */
-
-      /* FIXME: should use substring of get_emacs_configuration ().
-        But I don't think the Windows build supports alpha, mips etc
-         anymore, so have taken the easy option for now.  */
-      else if (p && (xstrcasecmp (p, "\\i386") == 0
-                     || xstrcasecmp (p, "\\AMD64") == 0))
-       {
-         *p = 0;
-         p = _mbsrchr (modname, '\\');
-         if (p != NULL)
-           {
-             *p = 0;
-             p = _mbsrchr (modname, '\\');
-             if (p && xstrcasecmp (p, "\\src") == 0)
-               {
-                 char buf[SET_ENV_BUF_SIZE];
-
-                 *p = 0;
-                 for (p = modname; *p; p = CharNext (p))
-                   if (*p == '\\') *p = '/';
-
-                 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
-                 _putenv (strdup (buf));
-               }
-           }
-       }
     }
 
     for (i = 0; i < N_ENV_VARS; i++)
@@ -2226,8 +2605,7 @@
                          strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
                          ExpandEnvironmentStrings ((LPSTR) fname, bufc,
                                                    sizeof (bufc));
-                         if (faccessat (AT_FDCWD, bufc, F_OK, AT_EACCESS)
-                             == 0)
+                         if (sys_access (bufc, F_OK) == 0)
                            {
                              lpval = bufc;
                              dwType = REG_SZ;
@@ -2307,13 +2685,27 @@
   /* Remember the initial working directory for getcwd.  */
   /* FIXME: Do we need to resolve possible symlinks in startup_dir?
      Does it matter anywhere in Emacs?  */
-  if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
-    emacs_abort ();
+  if (w32_unicode_filenames)
+    {
+      wchar_t wstartup_dir[MAX_PATH];
+
+      if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
+       emacs_abort ();
+      filename_from_utf16 (wstartup_dir, startup_dir);
+    }
+  else
+    {
+      char astartup_dir[MAX_PATH];
+
+      if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
+       emacs_abort ();
+      filename_from_ansi (astartup_dir, startup_dir);
+    }
 
   {
     static char modname[MAX_PATH];
 
-    if (!GetModuleFileName (NULL, modname, MAX_PATH))
+    if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
       emacs_abort ();
     argv[0] = modname;
   }
@@ -2331,170 +2723,18 @@
 char *
 emacs_root_dir (void)
 {
-  static char root_dir[FILENAME_MAX];
+  static char root_dir[MAX_UTF8_PATH];
   const char *p;
 
   p = getenv ("emacs_dir");
   if (p == NULL)
     emacs_abort ();
-  strcpy (root_dir, p);
+  filename_from_ansi (p, root_dir);
   root_dir[parse_root (root_dir, NULL)] = '\0';
-  dostounix_filename (root_dir, 0);
+  dostounix_filename (root_dir);
   return root_dir;
 }
 
-/* We don't have scripts to automatically determine the system configuration
-   for Emacs before it's compiled, and we don't want to have to make the
-   user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
-   routine.  */
-
-char *
-get_emacs_configuration (void)
-{
-  char *arch, *oem, *os;
-  int build_num;
-  static char configuration_buffer[32];
-
-  /* Determine the processor type.  */
-  switch (get_processor_type ())
-    {
-
-#ifdef PROCESSOR_INTEL_386
-    case PROCESSOR_INTEL_386:
-    case PROCESSOR_INTEL_486:
-    case PROCESSOR_INTEL_PENTIUM:
-#ifdef _WIN64
-      arch = "amd64";
-#else
-      arch = "i386";
-#endif
-      break;
-#endif
-#ifdef PROCESSOR_AMD_X8664
-    case PROCESSOR_AMD_X8664:
-      arch = "amd64";
-      break;
-#endif
-
-#ifdef PROCESSOR_MIPS_R2000
-    case PROCESSOR_MIPS_R2000:
-    case PROCESSOR_MIPS_R3000:
-    case PROCESSOR_MIPS_R4000:
-      arch = "mips";
-      break;
-#endif
-
-#ifdef PROCESSOR_ALPHA_21064
-    case PROCESSOR_ALPHA_21064:
-      arch = "alpha";
-      break;
-#endif
-
-    default:
-      arch = "unknown";
-      break;
-    }
-
-  /* Use the OEM field to reflect the compiler/library combination.  */
-#ifdef _MSC_VER
-#define COMPILER_NAME  "msvc"
-#else
-#ifdef __GNUC__
-#define COMPILER_NAME  "mingw"
-#else
-#define COMPILER_NAME  "unknown"
-#endif
-#endif
-  oem = COMPILER_NAME;
-
-  switch (osinfo_cache.dwPlatformId) {
-  case VER_PLATFORM_WIN32_NT:
-    os = "nt";
-    build_num = osinfo_cache.dwBuildNumber;
-    break;
-  case VER_PLATFORM_WIN32_WINDOWS:
-    if (osinfo_cache.dwMinorVersion == 0) {
-      os = "windows95";
-    } else {
-      os = "windows98";
-    }
-    build_num = LOWORD (osinfo_cache.dwBuildNumber);
-    break;
-  case VER_PLATFORM_WIN32s:
-    /* Not supported, should not happen. */
-    os = "windows32s";
-    build_num = LOWORD (osinfo_cache.dwBuildNumber);
-    break;
-  default:
-    os = "unknown";
-    build_num = 0;
-    break;
-  }
-
-  if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-    sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
-            get_w32_major_version (), get_w32_minor_version (), build_num);
-  } else {
-    sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
-  }
-
-  return configuration_buffer;
-}
-
-char *
-get_emacs_configuration_options (void)
-{
-  static char *options_buffer;
-  char cv[32];  /* Enough for COMPILER_VERSION.  */
-  char *options[] = {
-    cv,  /* To be filled later.  */
-#ifdef EMACSDEBUG
-    " --no-opt",
-#endif
-#ifdef ENABLE_CHECKING
-    " --enable-checking",
-#endif
-    /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
-       with a starting space to save work here.  */
-#ifdef USER_CFLAGS
-    " --cflags", USER_CFLAGS,
-#endif
-#ifdef USER_LDFLAGS
-    " --ldflags", USER_LDFLAGS,
-#endif
-    NULL
-  };
-  size_t size = 0;
-  int i;
-
-/* Work out the effective configure options for this build.  */
-#ifdef _MSC_VER
-#define COMPILER_VERSION       "--with-msvc (%d.%02d)", _MSC_VER / 100, 
_MSC_VER % 100
-#else
-#ifdef __GNUC__
-#define COMPILER_VERSION       "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
-#else
-#define COMPILER_VERSION       ""
-#endif
-#endif
-
-  if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
-    return "Error: not enough space for compiler version";
-  cv[sizeof (cv) - 1] = '\0';
-
-  for (i = 0; options[i]; i++)
-    size += strlen (options[i]);
-
-  options_buffer = xmalloc (size + 1);
-  options_buffer[0] = '\0';
-
-  for (i = 0; options[i]; i++)
-    strcat (options_buffer, options[i]);
-
-  return options_buffer;
-}
-
-
 #include <sys/timeb.h>
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
@@ -2649,6 +2889,7 @@
 add_volume_info (char * root_dir, volume_info_data * info)
 {
   info->root_dir = xstrdup (root_dir);
+  unixtodos_filename (info->root_dir);
   info->next = volume_cache;
   volume_cache = info;
 }
@@ -2661,14 +2902,30 @@
 GetCachedVolumeInformation (char * root_dir)
 {
   volume_info_data * info;
-  char default_root[ MAX_PATH ];
+  char default_root[ MAX_UTF8_PATH ];
+  char  name[MAX_PATH+1];
+  char  type[MAX_PATH+1];
 
   /* NULL for root_dir means use root from current directory.  */
   if (root_dir == NULL)
     {
-      if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
-       return NULL;
-      parse_root (default_root, &root_dir);
+      if (w32_unicode_filenames)
+       {
+         wchar_t curdirw[MAX_PATH];
+
+         if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
+           return NULL;
+         filename_from_utf16 (curdirw, default_root);
+       }
+      else
+       {
+         char curdira[MAX_PATH];
+
+         if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
+           return NULL;
+         filename_from_ansi (curdira, default_root);
+       }
+      parse_root (default_root, (const char **)&root_dir);
       *root_dir = 0;
       root_dir = default_root;
     }
@@ -2707,20 +2964,47 @@
 
   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
     {
-      char  name[ 256 ];
       DWORD serialnum;
       DWORD maxcomp;
       DWORD flags;
-      char  type[ 256 ];
 
       /* Info is not cached, or is stale. */
-      if (!GetVolumeInformation (root_dir,
-                                name, sizeof (name),
-                                &serialnum,
-                                &maxcomp,
-                                &flags,
-                                type, sizeof (type)))
-       return NULL;
+      if (w32_unicode_filenames)
+       {
+         wchar_t root_w[MAX_PATH];
+         wchar_t  name_w[MAX_PATH+1];
+         wchar_t  type_w[MAX_PATH+1];
+
+         filename_to_utf16 (root_dir, root_w);
+         if (!GetVolumeInformationW (root_w,
+                                    name_w, sizeof (name_w),
+                                    &serialnum,
+                                    &maxcomp,
+                                    &flags,
+                                    type_w, sizeof (type_w)))
+           return NULL;
+         /* Hmm... not really 100% correct, as these 2 are not file
+            names...  */
+         filename_from_utf16 (name_w, name);
+         filename_from_utf16 (type_w, type);
+       }
+      else
+       {
+         char root_a[MAX_PATH];
+         char  name_a[MAX_PATH+1];
+         char  type_a[MAX_PATH+1];
+
+         filename_to_ansi (root_dir, root_a);
+         if (!GetVolumeInformationA (root_a,
+                                    name_a, sizeof (name_a),
+                                    &serialnum,
+                                    &maxcomp,
+                                    &flags,
+                                    type_a, sizeof (type_a)))
+           return NULL;
+         filename_from_ansi (name_a, name);
+         filename_from_ansi (type_a, type);
+       }
 
       /* Cache the volume information for future use, overwriting existing
         entry if present.  */
@@ -2736,6 +3020,7 @@
        }
 
       info->name = xstrdup (name);
+      unixtodos_filename (info->name);
       info->serialnum = serialnum;
       info->maxcomp = maxcomp;
       info->flags = flags;
@@ -2758,52 +3043,22 @@
 static int
 get_volume_info (const char * name, const char ** pPath)
 {
-  char temp[MAX_PATH];
+  char temp[MAX_UTF8_PATH];
   char *rootname = NULL;  /* default to current volume */
   volume_info_data * info;
+  int root_len = parse_root (name, pPath);
 
   if (name == NULL)
     return FALSE;
 
-  /* Find the root name of the volume if given.  */
-  if (isalpha (name[0]) && name[1] == ':')
-    {
-      rootname = temp;
-      temp[0] = *name++;
-      temp[1] = *name++;
-      temp[2] = '\\';
-      temp[3] = 0;
-    }
-  else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
-    {
-      char *str = temp;
-      int slashes = 4;
-      int dbcs_p = max_filename_mbslen () > 1;
-
-      rootname = temp;
-      do
-        {
-         if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
-           break;
-         if (!dbcs_p)
-           *str++ = *name++;
-         else
-           {
-             const char *p = name;
-
-             name = CharNextExA (file_name_codepage, name, 0);
-             memcpy (str, p, name - p);
-             str += name - p;
-           }
-       }
-      while ( *name );
-
-      *str++ = '\\';
-      *str = 0;
-    }
-
-  if (pPath)
-    *pPath = name;
+  /* Copy the root name of the volume, if given.  */
+  if (root_len)
+    {
+      strncpy (temp, name, root_len);
+      temp[root_len] = '\0';
+      unixtodos_filename (temp);
+      rootname = temp;
+    }
 
   info = GetCachedVolumeInformation (rootname);
   if (info != NULL)
@@ -2826,18 +3081,19 @@
   return FALSE;
 }
 
-/* Map filename to a valid 8.3 name if necessary.
-   The result is a pointer to a static buffer, so CAVEAT EMPTOR!  */
+/* Convert all slashes in a filename to backslashes, and map filename
+   to a valid 8.3 name if necessary.  The result is a pointer to a
+   static buffer, so CAVEAT EMPTOR!  */
 const char *
 map_w32_filename (const char * name, const char ** pPath)
 {
-  static char shortname[MAX_PATH];
+  static char shortname[MAX_UTF8_PATH];
   char * str = shortname;
   char c;
   char * path;
   const char * save_name = name;
 
-  if (strlen (name) >= MAX_PATH)
+  if (strlen (name) >= sizeof (shortname))
     {
       /* Return a filename which will cause callers to fail.  */
       strcpy (shortname, "?");
@@ -2904,7 +3160,7 @@
                str[-1] = c;            /* replace last character of part */
              /* FALLTHRU */
            default:
-             if ( left )
+             if ( left && 'A' <= c && c <= 'Z' )
                {
                  *str++ = tolower (c); /* map to lower case (looks nicer) */
                  left--;
@@ -2939,25 +3195,31 @@
         xstrcasecmp (p, ".cmd") == 0));
 }
 
-/* Emulate the Unix directory procedures opendir, closedir,
-   and readdir.  We can't use the procedures supplied in sysdep.c,
-   so we provide them here.  */
+/* Emulate the Unix directory procedures opendir, closedir, and
+   readdir.  We rename them to sys_* names because some versions of
+   MinGW startup code call opendir and readdir to glob wildcards, and
+   the code that calls them doesn't grok UTF-8 encoded file names we
+   produce in dirent->d_name[].  */
 
 struct dirent dir_static;       /* simulated directory contents */
 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
 static int    dir_is_fat;
-static char   dir_pathname[MAXPATHLEN+1];
-static WIN32_FIND_DATA dir_find_data;
+static char   dir_pathname[MAX_UTF8_PATH];
+static WIN32_FIND_DATAW dir_find_data_w;
+static WIN32_FIND_DATAA dir_find_data_a;
+#define DIR_FIND_DATA_W 1
+#define DIR_FIND_DATA_A 2
+static int    last_dir_find_data = -1;
 
 /* Support shares on a network resource as subdirectories of a read-only
    root directory. */
 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
 static HANDLE open_unc_volume (const char *);
-static char  *read_unc_volume (HANDLE, char *, int);
+static void  *read_unc_volume (HANDLE, wchar_t *, char *, int);
 static void   close_unc_volume (HANDLE);
 
 DIR *
-opendir (const char *filename)
+sys_opendir (const char *filename)
 {
   DIR *dirp;
 
@@ -2986,8 +3248,8 @@
   dirp->dd_loc = 0;
   dirp->dd_size = 0;
 
-  strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
-  dir_pathname[MAXPATHLEN] = '\0';
+  strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
+  dir_pathname[MAX_UTF8_PATH - 1] = '\0';
   /* Note: We don't support symlinks to file names on FAT volumes.
      Doing so would mean punishing 99.99% of use cases by resolving
      all the possible symlinks in FILENAME, recursively.  */
@@ -2997,7 +3259,7 @@
 }
 
 void
-closedir (DIR *dirp)
+sys_closedir (DIR *dirp)
 {
   /* If we have a find-handle open, close it.  */
   if (dir_find_handle != INVALID_HANDLE_VALUE)
@@ -3014,52 +3276,65 @@
 }
 
 struct dirent *
-readdir (DIR *dirp)
+sys_readdir (DIR *dirp)
 {
   int downcase = !NILP (Vw32_downcase_file_names);
 
   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
     {
       if (!read_unc_volume (wnet_enum_handle,
-                            dir_find_data.cFileName,
+                            dir_find_data_w.cFileName,
+                            dir_find_data_a.cFileName,
                             MAX_PATH))
        return NULL;
     }
   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
   else if (dir_find_handle == INVALID_HANDLE_VALUE)
     {
-      char filename[MAXNAMLEN + 3];
+      char filename[MAX_UTF8_PATH + 2];
       int ln;
-      int dbcs_p = max_filename_mbslen () > 1;
 
       strcpy (filename, dir_pathname);
       ln = strlen (filename) - 1;
-      if (!dbcs_p)
-       {
-         if (!IS_DIRECTORY_SEP (filename[ln]))
-           strcat (filename, "\\");
-       }
-      else
-       {
-         char *end = filename + ln + 1;
-         char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
-
-         if (!IS_DIRECTORY_SEP (*last_char))
-           strcat (filename, "\\");
-       }
+      if (!IS_DIRECTORY_SEP (filename[ln]))
+       strcat (filename, "\\");
       strcat (filename, "*");
 
       /* Note: No need to resolve symlinks in FILENAME, because
         FindFirst opens the directory that is the target of a
         symlink.  */
-      dir_find_handle = FindFirstFile (filename, &dir_find_data);
+      if (w32_unicode_filenames)
+       {
+         wchar_t fnw[MAX_PATH];
+
+         filename_to_utf16 (filename, fnw);
+         dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
+       }
+      else
+       {
+         char fna[MAX_PATH];
+
+         filename_to_ansi (filename, fna);
+         /* If FILENAME is not representable by the current ANSI
+            codepage, we don't want FindFirstFileA to interpret the
+            '?' characters as a wildcard.  */
+         if (_mbspbrk (fna, "?"))
+           dir_find_handle = INVALID_HANDLE_VALUE;
+         else
+           dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
+       }
 
       if (dir_find_handle == INVALID_HANDLE_VALUE)
        return NULL;
     }
+  else if (w32_unicode_filenames)
+    {
+      if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
+       return NULL;
+    }
   else
     {
-      if (!FindNextFile (dir_find_handle, &dir_find_data))
+      if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
        return NULL;
     }
 
@@ -3067,112 +3342,155 @@
      value returned by stat().  */
   dir_static.d_ino = 1;
 
-  strcpy (dir_static.d_name, dir_find_data.cFileName);
-
-  /* If the file name in cFileName[] includes `?' characters, it means
-     the original file name used characters that cannot be represented
-     by the current ANSI codepage.  To avoid total lossage, retrieve
-     the short 8+3 alias of the long file name.  */
-  if (_mbspbrk (dir_static.d_name, "?"))
-    {
-      strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
-      downcase = 1;    /* 8+3 aliases are returned in all caps */
-    }
+  if (w32_unicode_filenames)
+    {
+      if (downcase || dir_is_fat)
+       {
+         wchar_t tem[MAX_PATH];
+
+         wcscpy (tem, dir_find_data_w.cFileName);
+         CharLowerW (tem);
+         filename_from_utf16 (tem, dir_static.d_name);
+       }
+      else
+       filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
+      last_dir_find_data = DIR_FIND_DATA_W;
+    }
+  else
+    {
+      char tem[MAX_PATH];
+
+      /* If the file name in cFileName[] includes `?' characters, it
+        means the original file name used characters that cannot be
+        represented by the current ANSI codepage.  To avoid total
+        lossage, retrieve the short 8+3 alias of the long file
+        name.  */
+      if (_mbspbrk (dir_find_data_a.cFileName, "?"))
+       {
+         strcpy (tem, dir_find_data_a.cAlternateFileName);
+         /* 8+3 aliases are returned in all caps, which could break
+            various alists that look at filenames' extensions.  */
+         downcase = 1;
+       }
+      else if (downcase || dir_is_fat)
+       strcpy (tem, dir_find_data_a.cFileName);
+      else
+       filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
+      if (downcase || dir_is_fat)
+       {
+         _mbslwr (tem);
+         filename_from_ansi (tem, dir_static.d_name);
+       }
+      last_dir_find_data = DIR_FIND_DATA_A;
+    }
+
   dir_static.d_namlen = strlen (dir_static.d_name);
-  dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
+  dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
     dir_static.d_namlen - dir_static.d_namlen % 4;
 
-  /* If the file name in cFileName[] includes `?' characters, it means
-     the original file name used characters that cannot be represented
-     by the current ANSI codepage.  To avoid total lossage, retrieve
-     the short 8+3 alias of the long file name.  */
-  if (_mbspbrk (dir_find_data.cFileName, "?"))
-    {
-      strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
-      /* 8+3 aliases are returned in all caps, which could break
-        various alists that look at filenames' extensions.  */
-      downcase = 1;
-    }
-  else
-    strcpy (dir_static.d_name, dir_find_data.cFileName);
-  dir_static.d_namlen = strlen (dir_static.d_name);
-  if (dir_is_fat)
-    _mbslwr (dir_static.d_name);
-  else if (downcase)
-    {
-      register char *p;
-      int dbcs_p = max_filename_mbslen () > 1;
-      for (p = dir_static.d_name; *p; )
-       {
-         if (*p >= 'a' && *p <= 'z')
-           break;
-         if (dbcs_p)
-           p = CharNextExA (file_name_codepage, p, 0);
-         else
-           p++;
-       }
-      if (!*p)
-       _mbslwr (dir_static.d_name);
-    }
-
   return &dir_static;
 }
 
 static HANDLE
 open_unc_volume (const char *path)
 {
-  NETRESOURCE nr;
+  const char *fn = map_w32_filename (path, NULL);
+  DWORD result;
   HANDLE henum;
-  int result;
-
-  nr.dwScope = RESOURCE_GLOBALNET;
-  nr.dwType = RESOURCETYPE_DISK;
-  nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
-  nr.dwUsage = RESOURCEUSAGE_CONTAINER;
-  nr.lpLocalName = NULL;
-  nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
-  nr.lpComment = NULL;
-  nr.lpProvider = NULL;
-
-  result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-                        RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
-
+
+  if (w32_unicode_filenames)
+    {
+      NETRESOURCEW nrw;
+      wchar_t fnw[MAX_PATH];
+
+      nrw.dwScope = RESOURCE_GLOBALNET;
+      nrw.dwType = RESOURCETYPE_DISK;
+      nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+      nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
+      nrw.lpLocalName = NULL;
+      filename_to_utf16 (fn, fnw);
+      nrw.lpRemoteName = fnw;
+      nrw.lpComment = NULL;
+      nrw.lpProvider = NULL;
+
+      result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+                             RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
+    }
+  else
+    {
+      NETRESOURCEA nra;
+      char fna[MAX_PATH];
+
+      nra.dwScope = RESOURCE_GLOBALNET;
+      nra.dwType = RESOURCETYPE_DISK;
+      nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+      nra.dwUsage = RESOURCEUSAGE_CONTAINER;
+      nra.lpLocalName = NULL;
+      filename_to_ansi (fn, fna);
+      nra.lpRemoteName = fna;
+      nra.lpComment = NULL;
+      nra.lpProvider = NULL;
+
+      result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+                             RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
+    }
   if (result == NO_ERROR)
     return henum;
   else
     return INVALID_HANDLE_VALUE;
 }
 
-static char *
-read_unc_volume (HANDLE henum, char *readbuf, int size)
+static void *
+read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
 {
   DWORD count;
   int result;
+  char *buffer;
   DWORD bufsize = 512;
-  char *buffer;
-  char *ptr;
-  int dbcs_p = max_filename_mbslen () > 1;
+  void *retval;
 
   count = 1;
-  buffer = alloca (bufsize);
-  result = WNetEnumResource (henum, &count, buffer, &bufsize);
-  if (result != NO_ERROR)
-    return NULL;
+  if (w32_unicode_filenames)
+    {
+      wchar_t *ptrw;
 
-  /* WNetEnumResource returns \\resource\share...skip forward to "share". */
-  ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
-  ptr += 2;
-  if (!dbcs_p)
-    while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
+      bufsize *= 2;
+      buffer = alloca (bufsize);
+      result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
+      if (result != NO_ERROR)
+       return NULL;
+      /* WNetEnumResource returns \\resource\share...skip forward to "share". 
*/
+      ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
+      ptrw += 2;
+      while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
+      ptrw++;
+      wcsncpy (fname_w, ptrw, size);
+      retval = fname_w;
+    }
   else
     {
-      while (*ptr && !IS_DIRECTORY_SEP (*ptr))
-       ptr = CharNextExA (file_name_codepage, ptr, 0);
+      int dbcs_p = max_filename_mbslen () > 1;
+      char *ptra;
+
+      buffer = alloca (bufsize);
+      result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
+      if (result != NO_ERROR)
+       return NULL;
+      ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
+      ptra += 2;
+      if (!dbcs_p)
+       while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
+      else
+       {
+         while (*ptra && !IS_DIRECTORY_SEP (*ptra))
+           ptra = CharNextExA (file_name_codepage, ptra, 0);
+       }
+      ptra++;
+      strncpy (fname_a, ptra, size);
+      retval = fname_a;
     }
-  ptr++;
 
-  strncpy (readbuf, ptr, size);
-  return readbuf;
+  return retval;
 }
 
 static void
@@ -3203,13 +3521,12 @@
 static void
 logon_network_drive (const char *path)
 {
-  NETRESOURCE resource;
-  char share[MAX_PATH];
+  char share[MAX_UTF8_PATH];
   int n_slashes;
   char drive[4];
   UINT drvtype;
   char *p;
-  int dbcs_p;
+  DWORD val;
 
   if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
     drvtype = DRIVE_REMOTE;
@@ -3229,28 +3546,70 @@
     return;
 
   n_slashes = 2;
-  strncpy (share, path, MAX_PATH);
+  strncpy (share, path, MAX_UTF8_PATH);
   /* Truncate to just server and share name.  */
-  dbcs_p = max_filename_mbslen () > 1;
-  for (p = share + 2; *p && p < share + MAX_PATH; )
+  for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
     {
       if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
         {
           *p = '\0';
           break;
         }
-      if (dbcs_p)
-       p = CharNextExA (file_name_codepage, p, 0);
-      else
-       p++;
-    }
-
-  resource.dwType = RESOURCETYPE_DISK;
-  resource.lpLocalName = NULL;
-  resource.lpRemoteName = share;
-  resource.lpProvider = NULL;
-
-  WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
+    }
+
+  if (w32_unicode_filenames)
+    {
+      NETRESOURCEW resourcew;
+      wchar_t share_w[MAX_PATH];
+
+      resourcew.dwScope = RESOURCE_GLOBALNET;
+      resourcew.dwType = RESOURCETYPE_DISK;
+      resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+      resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
+      resourcew.lpLocalName = NULL;
+      filename_to_utf16 (share, share_w);
+      resourcew.lpRemoteName = share_w;
+      resourcew.lpProvider = NULL;
+
+      val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
+    }
+  else
+    {
+      NETRESOURCEA resourcea;
+      char share_a[MAX_PATH];
+
+      resourcea.dwScope = RESOURCE_GLOBALNET;
+      resourcea.dwType = RESOURCETYPE_DISK;
+      resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+      resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
+      resourcea.lpLocalName = NULL;
+      filename_to_ansi (share, share_a);
+      resourcea.lpRemoteName = share_a;
+      resourcea.lpProvider = NULL;
+
+      val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
+    }
+
+  switch (val)
+    {
+    case NO_ERROR:
+    case ERROR_ALREADY_ASSIGNED:
+      break;
+    case ERROR_ACCESS_DENIED:
+    case ERROR_LOGON_FAILURE:
+      errno = EACCES;
+      break;
+    case ERROR_BUSY:
+      errno = EAGAIN;
+      break;
+    case ERROR_BAD_NET_NAME:
+    case ERROR_NO_NET_OR_BAD_PATH:
+    case ERROR_NO_NETWORK:
+    case ERROR_CANCELLED:
+    default:
+      errno = ENOENT;
+      break;
+    }
 }
 
 /* Emulate faccessat(2).  */
@@ -3278,7 +3637,22 @@
       && (flags & AT_SYMLINK_NOFOLLOW) == 0)
     path = chase_symlinks (path);
 
-  if ((attributes = GetFileAttributes (path)) == -1)
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      attributes = GetFileAttributesW (path_w);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      attributes = GetFileAttributesA (path_a);
+    }
+
+  if (attributes == -1)
     {
       DWORD w32err = GetLastError ();
 
@@ -3326,6 +3700,62 @@
   return 0;
 }
 
+/* A version of 'access' to be used locally with file names in
+   locale-specific encoding.  Does not resolve symlinks and does not
+   support file names on FAT12 and FAT16 volumes, but that's OK, since
+   we only invoke this function for files inside the Emacs source or
+   installation tree, on directories (so any symlinks should have the
+   directory bit set), and on short file names such as "C:/.emacs".  */
+static int
+sys_access (const char *fname, int mode)
+{
+  char fname_copy[MAX_PATH], *p;
+  DWORD attributes;
+
+  strcpy (fname_copy, fname);
+  /* Do the equivalent of unixtodos_filename.  */
+  for (p = fname_copy; *p; p = CharNext (p))
+    if (*p == '/')
+      *p = '\\';
+
+  if ((attributes = GetFileAttributesA (fname_copy)) == -1)
+    {
+      DWORD w32err = GetLastError ();
+
+      switch (w32err)
+       {
+       case ERROR_INVALID_NAME:
+       case ERROR_BAD_PATHNAME:
+       case ERROR_FILE_NOT_FOUND:
+       case ERROR_BAD_NETPATH:
+         errno = ENOENT;
+         break;
+       default:
+         errno = EACCES;
+         break;
+       }
+      return -1;
+    }
+  if ((mode & X_OK) != 0
+      && !(is_exec (fname_copy)
+          || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
+    {
+      errno = EACCES;
+      return -1;
+    }
+  if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
+    {
+      errno = EACCES;
+      return -1;
+    }
+  if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+    {
+      errno = EACCES;
+      return -1;
+    }
+  return 0;
+}
+
 /* Shadow some MSVC runtime functions to map requests for long filenames
    to reasonable short names if necessary.  This was originally added to
    permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
@@ -3334,20 +3764,63 @@
 int
 sys_chdir (const char * path)
 {
-  return _chdir (map_w32_filename (path, NULL));
+  path = map_w32_filename (path, NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t newdir_w[MAX_PATH];
+
+      if (filename_to_utf16 (path, newdir_w) == 0)
+       return _wchdir (newdir_w);
+      return -1;
+    }
+  else
+    {
+      char newdir_a[MAX_PATH];
+
+      if (filename_to_ansi (path, newdir_a) == 0)
+       return _chdir (newdir_a);
+      return -1;
+    }
 }
 
 int
 sys_chmod (const char * path, int mode)
 {
   path = chase_symlinks (map_w32_filename (path, NULL));
-  return _chmod (path, mode);
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      return _wchmod (path_w, mode);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      return _chmod (path_a, mode);
+    }
 }
 
 int
 sys_creat (const char * path, int mode)
 {
-  return _creat (map_w32_filename (path, NULL), mode);
+  path = map_w32_filename (path, NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      return _wcreat (path_w, mode);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      return _creat (path_a, mode);
+    }
 }
 
 FILE *
@@ -3387,7 +3860,21 @@
       }
     else break;
 
-  fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
+  path = map_w32_filename (path, NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
+    }
   if (fd < 0)
     return NULL;
 
@@ -3400,7 +3887,9 @@
 {
   HANDLE fileh;
   int   result = -1;
-  char oldname[MAX_PATH], newname[MAX_PATH];
+  char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
+  wchar_t oldname_w[MAX_PATH];
+  char oldname_a[MAX_PATH];
 
   if (old == NULL || new == NULL)
     {
@@ -3411,8 +3900,18 @@
   strcpy (oldname, map_w32_filename (old, NULL));
   strcpy (newname, map_w32_filename (new, NULL));
 
-  fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
-                     FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (w32_unicode_filenames)
+    {
+      filename_to_utf16 (oldname, oldname_w);
+      fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
+                          FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    }
+  else
+    {
+      filename_to_ansi (oldname, oldname_a);
+      fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
+                          FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    }
   if (fileh != INVALID_HANDLE_VALUE)
     {
       int wlen;
@@ -3429,7 +3928,10 @@
        WCHAR wbuffer[MAX_PATH];        /* extra space for link name */
       } data;
 
-      wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
+      /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
+        indicates that flag is unsupported for CP_UTF8, and OTOH says
+        it is the default anyway.  */
+      wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
                                  data.wid.cStreamName, MAX_PATH);
       if (wlen > 0)
        {
@@ -3453,9 +3955,40 @@
            }
          else
            {
-             /* Should try mapping GetLastError to errno; for now just
-                indicate a general error (eg. links not supported).  */
-             errno = EINVAL;  // perhaps EMLINK?
+             DWORD err = GetLastError ();
+             DWORD attributes;
+
+             switch (err)
+               {
+               case ERROR_ACCESS_DENIED:
+                 /* This is what happens when OLDNAME is a directory,
+                    since Windows doesn't support hard links to
+                    directories.  Posix says to set errno to EPERM in
+                    that case.  */
+                 if (w32_unicode_filenames)
+                   attributes = GetFileAttributesW (oldname_w);
+                 else
+                   attributes = GetFileAttributesA (oldname_a);
+                 if (attributes != -1
+                     && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+                   errno = EPERM;
+                 else if (attributes == -1
+                          && is_unc_volume (oldname)
+                          && unc_volume_file_attributes (oldname) != -1)
+                   errno = EPERM;
+                 else
+                   errno = EACCES;
+                 break;
+               case ERROR_TOO_MANY_LINKS:
+                 errno = EMLINK;
+                 break;
+               case ERROR_NOT_SAME_DEVICE:
+                 errno = EXDEV;
+                 break;
+               default:
+                 errno = EINVAL;
+                 break;
+               }
            }
        }
 
@@ -3470,7 +4003,22 @@
 int
 sys_mkdir (const char * path)
 {
-  return _mkdir (map_w32_filename (path, NULL));
+  path = map_w32_filename (path, NULL);
+
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      return _wmkdir (path_w);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      return _mkdir (path_a);
+    }
 }
 
 int
@@ -3479,13 +4027,29 @@
   const char* mpath = map_w32_filename (path, NULL);
   int res = -1;
 
-  /* If possible, try to open file without _O_CREAT, to be able to
-     write to existing hidden and system files.  Force all file
-     handles to be non-inheritable. */
-  if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
-    res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
-  if (res < 0)
-    res = _open (mpath, oflag | _O_NOINHERIT, mode);
+  if (w32_unicode_filenames)
+    {
+      wchar_t mpath_w[MAX_PATH];
+
+      filename_to_utf16 (mpath, mpath_w);
+      /* If possible, try to open file without _O_CREAT, to be able to
+        write to existing hidden and system files.  Force all file
+        handles to be non-inheritable. */
+      if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
+       res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+      if (res < 0)
+       res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
+    }
+  else
+    {
+      char mpath_a[MAX_PATH];
+
+      filename_to_ansi (mpath, mpath_a);
+      if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
+       res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+      if (res < 0)
+       res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
+    }
 
   return res;
 }
@@ -3555,9 +4119,10 @@
 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
 {
   BOOL result;
-  char temp[MAX_PATH];
+  char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
   int newname_dev;
   int oldname_dev;
+  bool have_temp_a = false;
 
   /* MoveFile on Windows 95 doesn't correctly change the short file name
      alias in a number of circumstances (it is not easy to predict when
@@ -3582,17 +4147,20 @@
       char * o;
       char * p;
       int    i = 0;
+      char oldname_a[MAX_PATH];
 
       oldname = map_w32_filename (oldname, NULL);
-      if ((o = strrchr (oldname, '\\')))
+      filename_to_ansi (oldname, oldname_a);
+      filename_to_ansi (temp, temp_a);
+      if ((o = strrchr (oldname_a, '\\')))
        o++;
       else
-       o = (char *) oldname;
+       o = (char *) oldname_a;
 
-      if ((p = strrchr (temp, '\\')))
+      if ((p = strrchr (temp_a, '\\')))
        p++;
       else
-       p = temp;
+       p = temp_a;
 
       do
        {
@@ -3600,12 +4168,13 @@
             seems to make the second rename work properly.  */
          sprintf (p, "_.%s.%u", o, i);
          i++;
-         result = rename (oldname, temp);
+         result = rename (oldname_a, temp_a);
        }
       /* This loop must surely terminate!  */
       while (result < 0 && errno == EEXIST);
       if (result < 0)
        return -1;
+      have_temp_a = true;
     }
 
   /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
@@ -3624,41 +4193,81 @@
   /* volume_info is set indirectly by map_w32_filename.  */
   newname_dev = volume_info.serialnum;
 
-  result = rename (temp, newname);
-
-  if (result < 0 && force)
-    {
-      DWORD w32err = GetLastError ();
-
-      if (errno == EACCES
-         && newname_dev != oldname_dev)
-       {
-         /* The implementation of `rename' on Windows does not return
-            errno = EXDEV when you are moving a directory to a
-            different storage device (ex. logical disk).  It returns
-            EACCES instead.  So here we handle such situations and
-            return EXDEV.  */
-         DWORD attributes;
-
-         if ((attributes = GetFileAttributes (temp)) != -1
-             && (attributes & FILE_ATTRIBUTE_DIRECTORY))
-           errno = EXDEV;
-       }
-      else if (errno == EEXIST)
-       {
-         if (_chmod (newname, 0666) != 0)
-           return result;
-         if (_unlink (newname) != 0)
-           return result;
-         result = rename (temp, newname);
-       }
-      else if (w32err == ERROR_PRIVILEGE_NOT_HELD
-              && is_symlink (temp))
-       {
-         /* This is Windows prohibiting the user from creating a
-            symlink in another place, since that requires
-            privileges.  */
-         errno = EPERM;
+  if (w32_unicode_filenames)
+    {
+      wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
+
+      filename_to_utf16 (temp, temp_w);
+      filename_to_utf16 (newname, newname_w);
+      result = _wrename (temp_w, newname_w);
+      if (result < 0 && force)
+       {
+         DWORD w32err = GetLastError ();
+
+         if (errno == EACCES
+             && newname_dev != oldname_dev)
+           {
+             /* The implementation of `rename' on Windows does not return
+                errno = EXDEV when you are moving a directory to a
+                different storage device (ex. logical disk).  It returns
+                EACCES instead.  So here we handle such situations and
+                return EXDEV.  */
+             DWORD attributes;
+
+             if ((attributes = GetFileAttributesW (temp_w)) != -1
+                 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
+               errno = EXDEV;
+           }
+         else if (errno == EEXIST)
+           {
+             if (_wchmod (newname_w, 0666) != 0)
+               return result;
+             if (_wunlink (newname_w) != 0)
+               return result;
+             result = _wrename (temp_w, newname_w);
+           }
+         else if (w32err == ERROR_PRIVILEGE_NOT_HELD
+                  && is_symlink (temp))
+           {
+             /* This is Windows prohibiting the user from creating a
+                symlink in another place, since that requires
+                privileges.  */
+             errno = EPERM;
+           }
+       }
+    }
+  else
+    {
+      char newname_a[MAX_PATH];
+
+      if (!have_temp_a)
+       filename_to_ansi (temp, temp_a);
+      filename_to_ansi (newname, newname_a);
+      result = rename (temp_a, newname_a);
+      if (result < 0 && force)
+       {
+         DWORD w32err = GetLastError ();
+
+         if (errno == EACCES
+             && newname_dev != oldname_dev)
+           {
+             DWORD attributes;
+
+             if ((attributes = GetFileAttributesA (temp_a)) != -1
+                 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
+               errno = EXDEV;
+           }
+         else if (errno == EEXIST)
+           {
+             if (_chmod (newname_a, 0666) != 0)
+               return result;
+             if (_unlink (newname_a) != 0)
+               return result;
+             result = rename (temp_a, newname_a);
+           }
+         else if (w32err == ERROR_PRIVILEGE_NOT_HELD
+                  && is_symlink (temp))
+           errno = EPERM;
        }
     }
 
@@ -3674,7 +4283,22 @@
 int
 sys_rmdir (const char * path)
 {
-  return _rmdir (map_w32_filename (path, NULL));
+  path = map_w32_filename (path, NULL);
+
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      return _wrmdir (path_w);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      return _rmdir (path_a);
+    }
 }
 
 int
@@ -3682,9 +4306,23 @@
 {
   path = map_w32_filename (path, NULL);
 
-  /* On Unix, unlink works without write permission. */
-  _chmod (path, 0666);
-  return _unlink (path);
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      /* On Unix, unlink works without write permission. */
+      _wchmod (path_w, 0666);
+      return _wunlink (path_w);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      _chmod (path_a, 0666);
+      return _unlink (path_a);
+    }
 }
 
 static FILETIME utc_base_ft;
@@ -3752,49 +4390,6 @@
   pft->dwLowDateTime = tmp.LowPart;
 }
 
-#if 0
-/* No reason to keep this; faking inode values either by hashing or even
-   using the file index from GetInformationByHandle, is not perfect and
-   so by default Emacs doesn't use the inode values on Windows.
-   Instead, we now determine file-truename correctly (except for
-   possible drive aliasing etc).  */
-
-/*  Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
-static unsigned
-hashval (const unsigned char * str)
-{
-  unsigned h = 0;
-  while (*str)
-    {
-      h = (h << 4) + *str++;
-      h ^= (h >> 28);
-    }
-  return h;
-}
-
-/* Return the hash value of the canonical pathname, excluding the
-   drive/UNC header, to get a hopefully unique inode number. */
-static DWORD
-generate_inode_val (const char * name)
-{
-  char fullname[ MAX_PATH ];
-  char * p;
-  unsigned hash;
-
-  /* Get the truly canonical filename, if it exists.  (Note: this
-     doesn't resolve aliasing due to subst commands, or recognize hard
-     links.  */
-  if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
-    emacs_abort ();
-
-  parse_root (fullname, &p);
-  /* Normal W32 filesystems are still case insensitive. */
-  _strlwr (p);
-  return hashval (p);
-}
-
-#endif
-
 static PSECURITY_DESCRIPTOR
 get_file_security_desc_by_handle (HANDLE h)
 {
@@ -4001,18 +4596,21 @@
 }
 
 /* If this is non-zero, the caller wants accurate information about
-   file's owner and group, which could be expensive to get.  */
+   file's owner and group, which could be expensive to get.  dired.c
+   uses this flag when needed for the job at hand.  */
 int w32_stat_get_owner_group;
 
 /* MSVC stat function can't cope with UNC names and has other bugs, so
    replace it with our own.  This also allows us to calculate consistent
-   inode values and owner/group without hacks in the main Emacs code. */
+   inode values and owner/group without hacks in the main Emacs code,
+   and support file names encoded in UTF-8. */
 
 static int
 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
 {
   char *name, *save_name, *r;
-  WIN32_FIND_DATA wfd;
+  WIN32_FIND_DATAW wfd_w;
+  WIN32_FIND_DATAA wfd_a;
   HANDLE fh;
   unsigned __int64 fake_inode = 0;
   int permission;
@@ -4024,7 +4622,8 @@
   DWORD access_rights = 0;
   DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
   FILETIME ctime, atime, wtime;
-  int dbcs_p;
+  wchar_t name_w[MAX_PATH];
+  char name_a[MAX_PATH];
 
   if (path == NULL || buf == NULL)
     {
@@ -4034,11 +4633,8 @@
 
   save_name = name = (char *) map_w32_filename (path, &path);
   /* Must be valid filename, no wild cards or other invalid
-     characters.  We use _mbspbrk to support multibyte strings that
-     might look to strpbrk as if they included literal *, ?, and other
-     characters mentioned below that are disallowed by Windows
-     filesystems.  */
-  if (_mbspbrk (name, "*?|<>\""))
+     characters.  */
+  if (strpbrk (name, "*?|<>\""))
     {
       errno = ENOENT;
       return -1;
@@ -4089,13 +4685,26 @@
       if (is_windows_9x () != TRUE)
        access_rights |= READ_CONTROL;
 
-      fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
-                      file_flags, NULL);
-      /* If CreateFile fails with READ_CONTROL, try again with zero as
-        access rights.  */
-      if (fh == INVALID_HANDLE_VALUE && access_rights)
-       fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
-                        file_flags, NULL);
+      if (w32_unicode_filenames)
+       {
+         filename_to_utf16 (name, name_w);
+         fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
+                          file_flags, NULL);
+         /* If CreateFile fails with READ_CONTROL, try again with
+            zero as access rights.  */
+         if (fh == INVALID_HANDLE_VALUE && access_rights)
+           fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
+                            file_flags, NULL);
+       }
+      else
+       {
+         filename_to_ansi (name, name_a);
+         fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
+                          file_flags, NULL);
+         if (fh == INVALID_HANDLE_VALUE && access_rights)
+           fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
+                            file_flags, NULL);
+       }
       if (fh == INVALID_HANDLE_VALUE)
        goto no_true_file_attributes;
 
@@ -4222,7 +4831,6 @@
         did not ask for extra precision, resolving symlinks will fly
         in the face of that request, since the user then wants the
         lightweight version of the code.  */
-      dbcs_p = max_filename_mbslen () > 1;
       rootdir = (path >= save_name + len - 1
                 && (IS_DIRECTORY_SEP (*path) || *path == 0));
 
@@ -4250,19 +4858,8 @@
        }
       else if (rootdir)
        {
-         if (!dbcs_p)
-           {
-             if (!IS_DIRECTORY_SEP (name[len-1]))
-               strcat (name, "\\");
-           }
-         else
-           {
-             char *end = name + len;
-             char *n = CharPrevExA (file_name_codepage, name, end, 0);
-
-             if (!IS_DIRECTORY_SEP (*n))
-               strcat (name, "\\");
-           }
+         if (!IS_DIRECTORY_SEP (name[len-1]))
+           strcat (name, "\\");
          if (GetDriveType (name) < 2)
            {
              errno = ENOENT;
@@ -4274,51 +4871,65 @@
        }
       else
        {
-         if (!dbcs_p)
-           {
-             if (IS_DIRECTORY_SEP (name[len-1]))
-               name[len - 1] = 0;
-           }
-         else
-           {
-             char *end = name + len;
-             char *n = CharPrevExA (file_name_codepage, name, end, 0);
+         int have_wfd = -1;
 
-             if (IS_DIRECTORY_SEP (*n))
-               *n = 0;
-           }
+         if (IS_DIRECTORY_SEP (name[len-1]))
+           name[len - 1] = 0;
 
          /* (This is hacky, but helps when doing file completions on
             network drives.)  Optimize by using information available from
             active readdir if possible.  */
          len = strlen (dir_pathname);
-         if (!dbcs_p)
-           {
-             if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
-               len--;
-           }
-         else
-           {
-             char *end = dir_pathname + len;
-             char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
-
-             if (IS_DIRECTORY_SEP (*n))
-               len--;
-           }
+         if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
+           len--;
          if (dir_find_handle != INVALID_HANDLE_VALUE
+             && last_dir_find_data != -1
              && !(is_a_symlink && follow_symlinks)
-             && strnicmp (save_name, dir_pathname, len) == 0
+             /* The 2 file-name comparisons below support only ASCII
+                characters, and will lose (compare not equal) when
+                the file names include non-ASCII charcaters that are
+                the same but for the case.  However, doing this
+                properly involves: (a) converting both file names to
+                UTF-16, (b) lower-casing both names using CharLowerW,
+                and (c) comparing the results; this would be quite a
+                bit slower, whereas Plan B is for users who want
+                lightweight albeit inaccurate version of 'stat'.  */
+             && c_strncasecmp (save_name, dir_pathname, len) == 0
              && IS_DIRECTORY_SEP (name[len])
              && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
            {
+             have_wfd = last_dir_find_data;
              /* This was the last entry returned by readdir.  */
-             wfd = dir_find_data;
+             if (last_dir_find_data == DIR_FIND_DATA_W)
+               wfd_w = dir_find_data_w;
+             else
+               wfd_a = dir_find_data_a;
            }
          else
            {
              logon_network_drive (name);
 
-             fh = FindFirstFile (name, &wfd);
+             if (w32_unicode_filenames)
+               {
+                 filename_to_utf16 (name, name_w);
+                 fh = FindFirstFileW (name_w, &wfd_w);
+                 have_wfd = DIR_FIND_DATA_W;
+               }
+             else
+               {
+                 filename_to_ansi (name, name_a);
+                 /* If NAME includes characters not representable by
+                    the current ANSI codepage, filename_to_ansi
+                    usually replaces them with a '?'.  We don't want
+                    to let FindFirstFileA interpret those as widlcards,
+                    and "succeed", returning us data from some random
+                    file in the same directory.  */
+                 if (_mbspbrk (name_a, "?"))
+                   fh = INVALID_HANDLE_VALUE;
+                 else
+                   fh = FindFirstFileA (name_a, &wfd_a);
+                 have_wfd = DIR_FIND_DATA_A;
+               }
              if (fh == INVALID_HANDLE_VALUE)
                {
                  errno = ENOENT;
@@ -4328,12 +4939,24 @@
            }
          /* Note: if NAME is a symlink, the information we get from
             FindFirstFile is for the symlink, not its target.  */
-         fattrs = wfd.dwFileAttributes;
-         ctime = wfd.ftCreationTime;
-         atime = wfd.ftLastAccessTime;
-         wtime = wfd.ftLastWriteTime;
-         fs_high = wfd.nFileSizeHigh;
-         fs_low = wfd.nFileSizeLow;
+         if (have_wfd == DIR_FIND_DATA_W)
+           {
+             fattrs = wfd_w.dwFileAttributes;
+             ctime = wfd_w.ftCreationTime;
+             atime = wfd_w.ftLastAccessTime;
+             wtime = wfd_w.ftLastWriteTime;
+             fs_high = wfd_w.nFileSizeHigh;
+             fs_low = wfd_w.nFileSizeLow;
+           }
+         else
+           {
+             fattrs = wfd_a.dwFileAttributes;
+             ctime = wfd_a.ftCreationTime;
+             atime = wfd_a.ftLastAccessTime;
+             wtime = wfd_a.ftLastWriteTime;
+             fs_high = wfd_a.nFileSizeHigh;
+             fs_low = wfd_a.nFileSizeLow;
+           }
          fake_inode = 0;
          nlinks = 1;
          serialnum = volume_info.serialnum;
@@ -4348,18 +4971,6 @@
       get_file_owner_and_group (NULL, buf);
     }
 
-#if 0
-  /* Not sure if there is any point in this.  */
-  if (!NILP (Vw32_generate_fake_inodes))
-    fake_inode = generate_inode_val (name);
-  else if (fake_inode == 0)
-    {
-      /* For want of something better, try to make everything unique.  */
-      static DWORD gen_num = 0;
-      fake_inode = ++gen_num;
-    }
-#endif
-
   buf->st_ino = fake_inode;
 
   buf->st_dev = serialnum;
@@ -4418,7 +5029,7 @@
 
      FIXME: Add proper support for fdopendir, fstatat, readlinkat.
      Gnulib does this and can serve as a model.  */
-  char fullname[MAX_PATH];
+  char fullname[MAX_UTF8_PATH];
 
   if (fd != AT_FDCWD)
     {
@@ -4563,13 +5174,32 @@
       times = &deftime;
     }
 
-  /* Need write access to set times.  */
-  fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
-                  /* If NAME specifies a directory, FILE_SHARE_DELETE
-                     allows other processes to delete files inside it,
-                     while we have the directory open.  */
-                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                  0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t name_utf16[MAX_PATH];
+
+      if (filename_to_utf16 (name, name_utf16) != 0)
+       return -1;      /* errno set by filename_to_utf16 */
+
+      /* Need write access to set times.  */
+      fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
+                       /* If NAME specifies a directory, FILE_SHARE_DELETE
+                          allows other processes to delete files inside it,
+                          while we have the directory open.  */
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    }
+  else
+    {
+      char name_ansi[MAX_PATH];
+
+      if (filename_to_ansi (name, name_ansi) != 0)
+       return -1;      /* errno set by filename_to_ansi */
+
+      fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                       0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+    }
   if (fh != INVALID_HANDLE_VALUE)
     {
       convert_from_time_t (times->actime, &atime);
@@ -4584,7 +5214,31 @@
     }
   else
     {
-      errno = EINVAL;
+      DWORD err = GetLastError ();
+
+      switch (err)
+       {
+       case ERROR_FILE_NOT_FOUND:
+       case ERROR_PATH_NOT_FOUND:
+       case ERROR_INVALID_DRIVE:
+       case ERROR_BAD_NETPATH:
+       case ERROR_DEV_NOT_EXIST:
+         /* ERROR_INVALID_NAME is the error CreateFile sets when the
+            file name includes ?s, i.e. translation to ANSI failed.  */
+       case ERROR_INVALID_NAME:
+         errno = ENOENT;
+         break;
+       case ERROR_TOO_MANY_OPEN_FILES:
+         errno = ENFILE;
+         break;
+       case ERROR_ACCESS_DENIED:
+       case ERROR_SHARING_VIOLATION:
+         errno = EACCES;
+         break;
+       default:
+         errno = EINVAL;
+         break;
+       }
       return -1;
     }
   return 0;
@@ -4599,10 +5253,9 @@
 int
 symlink (char const *filename, char const *linkname)
 {
-  char linkfn[MAX_PATH], *tgtfn;
+  char linkfn[MAX_UTF8_PATH], *tgtfn;
   DWORD flags = 0;
   int dir_access, filename_ends_in_slash;
-  int dbcs_p;
 
   /* Diagnostics follows Posix as much as possible.  */
   if (filename == NULL || linkname == NULL)
@@ -4615,7 +5268,7 @@
       errno = ENOENT;
       return -1;
     }
-  if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
+  if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
     {
       errno = ENAMETOOLONG;
       return -1;
@@ -4628,8 +5281,6 @@
       return -1;
     }
 
-  dbcs_p = max_filename_mbslen () > 1;
-
   /* Note: since empty FILENAME was already rejected, we can safely
      refer to FILENAME[1].  */
   if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
@@ -4641,24 +5292,11 @@
         directory where the Emacs process runs.  Note that
         make-symbolic-link always makes sure LINKNAME is a fully
         expanded file name.  */
-      char tem[MAX_PATH];
+      char tem[MAX_UTF8_PATH];
       char *p = linkfn + strlen (linkfn);
 
-      if (!dbcs_p)
-       {
-         while (p > linkfn && !IS_ANY_SEP (p[-1]))
-           p--;
-       }
-      else
-       {
-         char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
-
-         while (p > linkfn && !IS_ANY_SEP (*p1))
-           {
-             p = p1;
-             p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
-           }
-       }
+      while (p > linkfn && !IS_ANY_SEP (p[-1]))
+       p--;
       if (p > linkfn)
        strncpy (tem, linkfn, p - linkfn);
       tem[p - linkfn] = '\0';
@@ -4673,15 +5311,7 @@
      exist, but ends in a slash, we create a symlink to directory.  If
      FILENAME exists and is a directory, we always create a symlink to
      directory.  */
-  if (!dbcs_p)
-    filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 
1]);
-  else
-    {
-      const char *end = filename + strlen (filename);
-      const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
-
-      filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
-    }
+  filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
   if (dir_access == 0 || filename_ends_in_slash)
     flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
 
@@ -4751,10 +5381,23 @@
 is_symlink (const char *filename)
 {
   DWORD attrs;
-  WIN32_FIND_DATA wfd;
+  wchar_t filename_w[MAX_PATH];
+  char filename_a[MAX_PATH];
+  WIN32_FIND_DATAW wfdw;
+  WIN32_FIND_DATAA wfda;
   HANDLE fh;
+  int attrs_mean_symlink;
 
-  attrs = GetFileAttributes (filename);
+  if (w32_unicode_filenames)
+    {
+      filename_to_utf16 (filename, filename_w);
+      attrs = GetFileAttributesW (filename_w);
+    }
+  else
+    {
+      filename_to_ansi (filename, filename_a);
+      attrs = GetFileAttributesA (filename_a);
+    }
   if (attrs == -1)
     {
       DWORD w32err = GetLastError ();
@@ -4777,12 +5420,30 @@
   if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
     return 0;
   logon_network_drive (filename);
-  fh = FindFirstFile (filename, &wfd);
+  if (w32_unicode_filenames)
+    {
+      fh = FindFirstFileW (filename_w, &wfdw);
+      attrs_mean_symlink =
+       (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
+       && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == 
IO_REPARSE_TAG_SYMLINK;
+    }
+  else if (_mbspbrk (filename_a, "?"))
+    {
+      /* filename_to_ansi failed to convert the file name.  */
+      errno = ENOENT;
+      return 0;
+    }
+  else
+    {
+      fh = FindFirstFileA (filename_a, &wfda);
+      attrs_mean_symlink =
+       (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
+       && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == 
IO_REPARSE_TAG_SYMLINK;
+    }
   if (fh == INVALID_HANDLE_VALUE)
     return 0;
   FindClose (fh);
-  return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
-         && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == 
IO_REPARSE_TAG_SYMLINK;
+  return attrs_mean_symlink;
 }
 
 /* If NAME identifies a symbolic link, copy into BUF the file name of
@@ -4799,6 +5460,7 @@
   int restore_privs = 0;
   HANDLE sh;
   ssize_t retval;
+  char resolved[MAX_UTF8_PATH];
 
   if (name == NULL)
     {
@@ -4813,7 +5475,7 @@
 
   path = map_w32_filename (name, NULL);
 
-  if (strlen (path) > MAX_PATH)
+  if (strlen (path) > MAX_UTF8_PATH)
     {
       errno = ENAMETOOLONG;
       return -1;
@@ -4843,9 +5505,26 @@
      e.g. 'C:\Users\All Users', GENERIC_READ fails with
      ERROR_ACCESS_DENIED.  Zero seems to work just fine, both for file
      and directory symlinks.  */
-  sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
-                  FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
-                  NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t path_w[MAX_PATH];
+
+      filename_to_utf16 (path, path_w);
+      sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
+                       FILE_FLAG_OPEN_REPARSE_POINT
+                       | FILE_FLAG_BACKUP_SEMANTICS,
+                       NULL);
+    }
+  else
+    {
+      char path_a[MAX_PATH];
+
+      filename_to_ansi (path, path_a);
+      sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
+                       FILE_FLAG_OPEN_REPARSE_POINT
+                       | FILE_FLAG_BACKUP_SEMANTICS,
+                       NULL);
+    }
   if (sh != INVALID_HANDLE_VALUE)
     {
       BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
@@ -4864,89 +5543,27 @@
             reparse_data, then convert it to multibyte encoding in
             the current locale's codepage.  */
          WCHAR *lwname;
-         BYTE  lname[MAX_PATH];
-         USHORT lname_len;
+         size_t lname_size;
          USHORT lwname_len =
            reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
          WCHAR *lwname_src =
            reparse_data->SymbolicLinkReparseBuffer.PathBuffer
            + 
reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
-         /* This updates file_name_codepage which we need below.  */
-         int dbcs_p = max_filename_mbslen () > 1;
+         size_t size_to_copy = buf_size;
 
          /* According to MSDN, PrintNameLength does not include the
             terminating null character.  */
          lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
          memcpy (lwname, lwname_src, lwname_len);
          lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
-
-         lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1,
-                                          lname, MAX_PATH, NULL, NULL);
-         if (!lname_len)
-           {
-             /* WideCharToMultiByte failed.  */
-             DWORD w32err1 = GetLastError ();
-
-             switch (w32err1)
-               {
-               case ERROR_INSUFFICIENT_BUFFER:
-                 errno = ENAMETOOLONG;
-                 break;
-               case ERROR_INVALID_PARAMETER:
-                 errno = EFAULT;
-                 break;
-               case ERROR_NO_UNICODE_TRANSLATION:
-                 errno = ENOENT;
-                 break;
-               default:
-                 errno = EINVAL;
-                 break;
-               }
-           }
-         else
-           {
-             size_t size_to_copy = buf_size;
-             BYTE *p = lname, *p2;
-             BYTE *pend = p + lname_len;
-
-             /* Normalize like dostounix_filename does, but we don't
-                want to assume that lname is null-terminated.  */
-             if (dbcs_p)
-               p2 = CharNextExA (file_name_codepage, p, 0);
-             else
-               p2 = p + 1;
-             if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
-               {
-                 *p += 'a' - 'A';
-                 p += 2;
-               }
-             while (p <= pend)
-               {
-                 if (*p == '\\')
-                   *p = '/';
-                 if (dbcs_p)
-                   {
-                     p = CharNextExA (file_name_codepage, p, 0);
-                     /* CharNextExA doesn't advance at null character.  */
-                     if (!*p)
-                       break;
-                   }
-                 else
-                   ++p;
-               }
-             /* Testing for null-terminated LNAME is paranoia:
-                WideCharToMultiByte should always return a
-                null-terminated string when its 4th argument is -1
-                and its 3rd argument is null-terminated (which they
-                are, see above).  */
-             if (lname[lname_len - 1] == '\0')
-               lname_len--;
-             if (lname_len <= buf_size)
-               size_to_copy = lname_len;
-             strncpy (buf, lname, size_to_copy);
-             /* Success!  */
-             retval = size_to_copy;
-           }
+         filename_from_utf16 (lwname, resolved);
+         dostounix_filename (resolved);
+         lname_size = strlen (resolved) + 1;
+         if (lname_size <= buf_size)
+           size_to_copy = lname_size;
+         strncpy (buf, resolved, size_to_copy);
+         /* Success!  */
+         retval = size_to_copy;
        }
       CloseHandle (sh);
     }
@@ -4985,7 +5602,7 @@
 {
   /* Rely on a hack: an open directory is modeled as file descriptor 0,
      as in fstatat.  FIXME: Add proper support for readlinkat.  */
-  char fullname[MAX_PATH];
+  char fullname[MAX_UTF8_PATH];
 
   if (fd != AT_FDCWD)
     {
@@ -5024,41 +5641,45 @@
 static char *
 chase_symlinks (const char *file)
 {
-  static char target[MAX_PATH];
-  char link[MAX_PATH];
+  static char target[MAX_UTF8_PATH];
+  char link[MAX_UTF8_PATH];
+  wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
+  char target_a[MAX_PATH], link_a[MAX_PATH];
   ssize_t res, link_len;
   int loop_count = 0;
-  int dbcs_p;
 
   if (is_windows_9x () == TRUE || !is_symlink (file))
     return (char *)file;
 
-  if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
-    return (char *)file;
-
-  dbcs_p = max_filename_mbslen () > 1;
+  if (w32_unicode_filenames)
+    {
+      wchar_t file_w[MAX_PATH];
+
+      filename_to_utf16 (file, file_w);
+      if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
+       return (char *)file;
+      filename_from_utf16 (link_w, link);
+    }
+  else
+    {
+      char file_a[MAX_PATH];
+
+      filename_to_ansi (file, file_a);
+      if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
+       return (char *)file;
+      filename_from_ansi (link_a, link);
+    }
+  link_len = strlen (link);
+
   target[0] = '\0';
   do {
 
     /* Remove trailing slashes, as we want to resolve the last
        non-trivial part of the link name.  */
-    if (!dbcs_p)
-      {
-       while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
-         link[link_len--] = '\0';
-      }
-    else if (link_len > 3)
-      {
-       char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
-
-       while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
-         {
-           n[1] = '\0';
-           n = CharPrevExA (file_name_codepage, link, n, 0);
-         }
-      }
-
-    res = readlink (link, target, MAX_PATH);
+    while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
+      link[link_len--] = '\0';
+
+    res = readlink (link, target, MAX_UTF8_PATH);
     if (res > 0)
       {
        target[res] = '\0';
@@ -5069,27 +5690,28 @@
               the symlink, then copy the result back to target.  */
            char *p = link + link_len;
 
-           if (!dbcs_p)
-             {
-               while (p > link && !IS_ANY_SEP (p[-1]))
-                 p--;
-             }
-           else
-             {
-               char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
-
-               while (p > link && !IS_ANY_SEP (*p1))
-                 {
-                   p = p1;
-                   p1 = CharPrevExA (file_name_codepage, link, p1, 0);
-                 }
-             }
+           while (p > link && !IS_ANY_SEP (p[-1]))
+             p--;
            strcpy (p, target);
            strcpy (target, link);
          }
        /* Resolve any "." and ".." to get a fully-qualified file name
           in link[] again. */
-       link_len = GetFullPathName (target, MAX_PATH, link, NULL);
+       if (w32_unicode_filenames)
+         {
+           filename_to_utf16 (target, target_w);
+           link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
+           if (link_len > 0)
+             filename_from_utf16 (link_w, link);
+         }
+       else
+         {
+           filename_to_ansi (target, target_a);
+           link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
+           if (link_len > 0)
+             filename_from_ansi (link_a, link);
+         }
+       link_len = strlen (link);
       }
   } while (res > 0 && link_len > 0 && ++loop_count <= 100);
 
@@ -5206,7 +5828,11 @@
                }
            }
          else if (err == ERROR_FILE_NOT_FOUND
-                  || err == ERROR_PATH_NOT_FOUND)
+                  || err == ERROR_PATH_NOT_FOUND
+                  /* ERROR_INVALID_NAME is what we get if
+                     w32-unicode-filenames is nil and the file cannot
+                     be encoded in the current ANSI codepage. */
+                  || err == ERROR_INVALID_NAME)
            errno = ENOENT;
          else
            errno = EIO;
@@ -5284,7 +5910,7 @@
 
   e = errno;
   errno = 0;
-  if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
+  if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
     {
       err = GetLastError ();
 
@@ -5317,7 +5943,12 @@
              acl_free (current_acl);
            }
        }
-      else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+      else if (err == ERROR_FILE_NOT_FOUND
+              || err == ERROR_PATH_NOT_FOUND
+              /* ERROR_INVALID_NAME is what we get if
+                 w32-unicode-filenames is nil and the file cannot be
+                 encoded in the current ANSI codepage. */
+              || err == ERROR_INVALID_NAME)
        errno = ENOENT;
       else
        errno = EACCES;
@@ -5350,7 +5981,7 @@
               struct allocator const *alloc,
               ssize_t (*preadlinkat) (int, char const *, char *, size_t))
 {
-  char linkname[MAX_PATH];
+  char linkname[MAX_UTF8_PATH];
   ssize_t link_size;
 
   link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
@@ -7753,7 +8384,7 @@
 HMODULE
 w32_delayed_load (Lisp_Object library_id)
 {
-  HMODULE library_dll = NULL;
+  HMODULE dll_handle = NULL;
 
   CHECK_SYMBOL (library_id);
 
@@ -7766,26 +8397,56 @@
       if (CONSP (dlls))
         for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
           {
-            CHECK_STRING_CAR (dlls);
-            if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
-              {
-                char name[MAX_PATH];
-                DWORD len;
-
-                len = GetModuleFileNameA (library_dll, name, sizeof (name));
-                found = Fcons (XCAR (dlls),
-                               (len > 0)
-                               /* Possibly truncated */
-                               ? make_specified_string (name, -1, len, 1)
-                               : Qnil);
-                break;
-              }
-          }
+           Lisp_Object dll = XCAR (dlls);
+           char name[MAX_UTF8_PATH];
+           DWORD res = -1;
+
+           CHECK_STRING (dll);
+           dll = ENCODE_FILE (dll);
+           if (w32_unicode_filenames)
+             {
+               wchar_t name_w[MAX_PATH];
+
+               filename_to_utf16 (SSDATA (dll), name_w);
+               dll_handle = LoadLibraryW (name_w);
+               if (dll_handle)
+                 {
+                   res = GetModuleFileNameW (dll_handle, name_w,
+                                             sizeof (name_w));
+                   if (res > 0)
+                     filename_from_utf16 (name_w, name);
+                 }
+             }
+           else
+             {
+               char name_a[MAX_PATH];
+
+               filename_to_ansi (SSDATA (dll), name_a);
+               dll_handle = LoadLibraryA (name_a);
+               if (dll_handle)
+                 {
+                   res = GetModuleFileNameA (dll_handle, name_a,
+                                             sizeof (name_a));
+                   if (res > 0)
+                     filename_from_ansi (name_a, name);
+                 }
+             }
+           if (dll_handle)
+             {
+               ptrdiff_t len = strlen (name);
+               found = Fcons (dll,
+                              (res > 0)
+                              /* Possibly truncated */
+                              ? make_specified_string (name, -1, len, 1)
+                              : Qnil);
+               break;
+             }
+         }
 
       Fput (library_id, QCloaded_from, found);
     }
 
-  return library_dll;
+  return dll_handle;
 }
 
 
@@ -7804,6 +8465,12 @@
       Lisp_Object init_file;
       int fd;
 
+      /* Implementation note: this function runs early during Emacs
+        startup, before startup.el is run.  So Vload_path is still in
+        its initial unibyte form, but it holds UTF-8 encoded file
+        names, since init_callproc was already called.  So we do not
+        need to ENCODE_FILE here, but we do need to convert the file
+        names from UTF-8 to ANSI.  */
       init_file = build_string ("term/w32-win");
       fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
       if (fd < 0)
@@ -7814,6 +8481,8 @@
          char *buffer = alloca (1024
                                 + strlen (init_file_name)
                                 + strlen (load_path));
+         char *msg = buffer;
+         int needed;
 
          sprintf (buffer,
                   "The Emacs Windows initialization file \"%s.el\" "
@@ -7825,8 +8494,27 @@
                   "not unpacked properly.\nSee the README.W32 file in the "
                   "top-level Emacs directory for more information.",
                   init_file_name, load_path);
+         needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
+                                       -1, NULL, 0);
+         if (needed > 0)
+           {
+             wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
+
+             MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
+                                  msg_w, needed);
+             needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
+                                           NULL, 0, NULL, NULL);
+             if (needed > 0)
+               {
+                 char *msg_a = alloca (needed + 1);
+
+                 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
+                                      NULL, NULL);
+                 msg = msg_a;
+               }
+           }
          MessageBox (NULL,
-                     buffer,
+                     msg,
                      "Emacs Abort Dialog",
                      MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
          /* Use the low-level system abort. */
@@ -8002,7 +8690,8 @@
   g_b_init_get_sid_sub_authority = 0;
   g_b_init_get_sid_sub_authority_count = 0;
   g_b_init_get_security_info = 0;
-  g_b_init_get_file_security = 0;
+  g_b_init_get_file_security_w = 0;
+  g_b_init_get_file_security_a = 0;
   g_b_init_get_security_descriptor_owner = 0;
   g_b_init_get_security_descriptor_group = 0;
   g_b_init_is_valid_sid = 0;
@@ -8021,12 +8710,14 @@
   g_b_init_get_length_sid = 0;
   g_b_init_get_native_system_info = 0;
   g_b_init_get_system_times = 0;
-  g_b_init_create_symbolic_link = 0;
+  g_b_init_create_symbolic_link_w = 0;
+  g_b_init_create_symbolic_link_a = 0;
   g_b_init_get_security_descriptor_dacl = 0;
   g_b_init_convert_sd_to_sddl = 0;
   g_b_init_convert_sddl_to_sd = 0;
   g_b_init_is_valid_security_descriptor = 0;
-  g_b_init_set_file_security = 0;
+  g_b_init_set_file_security_w = 0;
+  g_b_init_set_file_security_a = 0;
   g_b_init_get_adapters_info = 0;
   num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
@@ -8040,6 +8731,14 @@
 
   /* Reset, in case it has some value inherited from dump time.  */
   w32_stat_get_owner_group = 0;
+
+  /* If w32_unicode_filenames is non-zero, we will be using Unicode
+     (a.k.a. "wide") APIs to invoke functions that accept file
+     names.  */
+  if (is_windows_9x ())
+    w32_unicode_filenames = 0;
+  else
+    w32_unicode_filenames = 1;
 }
 
 /* For make-serial-process  */

=== modified file 'src/w32.h'
--- a/src/w32.h 2013-08-29 15:32:04 +0000
+++ b/src/w32.h 2013-12-03 15:29:48 +0000
@@ -103,12 +103,6 @@
   OVERLAPPED          ovl_read;
   /* Used for async write operations on serial comm ports.  */
   OVERLAPPED          ovl_write;
-  /* Input file, if any, for this subprocess.  Should only be non-NULL
-     for async subprocesses.  */
-  char               *input_file;
-  /* If non-zero, the subprocess input file is temporary and should be
-     deleted when the subprocess exits.  */
-  int                 pending_deletion;
 } child_process;
 
 #define MAXDESC FD_SETSIZE
@@ -152,6 +146,9 @@
 /* Get long (aka "true") form of file name, if it exists.  */
 extern BOOL w32_get_long_filename (char * name, char * buf, int size);
 
+/* Get the short (a.k.a. "8+3") form of a file name.  */
+extern unsigned int w32_get_short_filename (char *, char *, int);
+
 /* Prepare our standard handles for proper inheritance by child processes.  */
 extern void prepare_standard_handles (int in, int out,
                                      int err, HANDLE handles[4]);
@@ -181,8 +178,14 @@
 extern void check_windows_init_file (void);
 extern void syms_of_ntproc (void);
 extern void syms_of_ntterm (void);
-extern void dostounix_filename (register char *, int);
+extern void dostounix_filename (register char *);
 extern void unixtodos_filename (register char *);
+extern int  filename_from_ansi (const char *, char *);
+extern int  filename_to_ansi (const char *, char *);
+extern int  filename_from_utf16 (const wchar_t *, char *);
+extern int  filename_to_utf16 (const char *, wchar_t *);
+extern Lisp_Object ansi_encode_filename (Lisp_Object);
+
 extern BOOL init_winsock (int load_now);
 extern void srandom (int);
 extern int random (void);
@@ -194,14 +197,10 @@
 extern void set_process_dir (char *);
 extern int sys_spawnve (int, char *, char **, char **);
 extern void register_child (pid_t, int);
-extern void record_infile (pid_t, char *);
-extern void record_pending_deletion (char *);
 
 extern void sys_sleep (int);
 extern int sys_link (const char *, const char *);
 
-
-
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
 

=== modified file 'src/w32fns.c'
--- a/src/w32fns.c      2013-12-02 17:28:17 +0000
+++ b/src/w32fns.c      2013-12-11 17:17:49 +0000
@@ -51,6 +51,7 @@
 
 #ifdef WINDOWSNT
 #include "w32heap.h"
+#include <mbstring.h>
 #endif /* WINDOWSNT */
 
 #if CYGWIN
@@ -6305,18 +6306,31 @@
 {
   if (msg == WM_NOTIFY)
     {
+      OFNOTIFYW * notify_w = (OFNOTIFYW *)lParam;
+      OFNOTIFYA * notify_a = (OFNOTIFYA *)lParam;
+      int dropdown_changed;
+      int dir_index;
 #ifdef NTGUI_UNICODE
-      OFNOTIFYW * notify = (OFNOTIFYW *)lParam;
+      const int use_unicode = 1;
 #else /* !NTGUI_UNICODE */
-      OFNOTIFYA * notify = (OFNOTIFYA *)lParam;
+      int use_unicode = w32_unicode_filenames;
 #endif /* NTGUI_UNICODE */
+
       /* Detect when the Filter dropdown is changed.  */
-      if (notify->hdr.code == CDN_TYPECHANGE
-         || notify->hdr.code == CDN_INITDONE)
+      if (use_unicode)
+       dropdown_changed =
+         notify_w->hdr.code == CDN_TYPECHANGE
+         || notify_w->hdr.code == CDN_INITDONE;
+      else
+       dropdown_changed =
+         notify_a->hdr.code == CDN_TYPECHANGE
+         || notify_a->hdr.code == CDN_INITDONE;
+      if (dropdown_changed)
        {
          HWND dialog = GetParent (hwnd);
          HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
          HWND list = GetDlgItem (dialog, FILE_NAME_LIST);
+         int hdr_code;
 
          /* At least on Windows 7, the above attempt to get the window handle
             to the File Name Text Field fails.  The following code does the
@@ -6334,10 +6348,24 @@
            }
 
          /* Directories is in index 2.  */
-         if (notify->lpOFN->nFilterIndex == 2)
-           {
-             CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
-                                              GUISTR ("Current Directory"));
+         if (use_unicode)
+           {
+             dir_index = notify_w->lpOFN->nFilterIndex;
+             hdr_code = notify_w->hdr.code;
+           }
+         else
+           {
+             dir_index = notify_a->lpOFN->nFilterIndex;
+             hdr_code = notify_a->hdr.code;
+           }
+         if (dir_index == 2)
+           {
+             if (use_unicode)
+               SendMessageW (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
+                             (LPARAM)L"Current Directory");
+             else
+               SendMessageA (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
+                             (LPARAM)"Current Directory");
              EnableWindow (edit_control, FALSE);
              /* Note that at least on Windows 7, the above call to EnableWindow
                 disables the window that would ordinarily have focus.  If we
@@ -6345,16 +6373,21 @@
                 no man's land and the user will be unable to tab through the
                 dialog box (pressing tab will only result in a beep).
                 Avoid that problem by setting focus to the list here.  */
-             if (notify->hdr.code == CDN_INITDONE)
+             if (hdr_code == CDN_INITDONE)
                SetFocus (list);
            }
          else
            {
              /* Don't override default filename on init done.  */
-             if (notify->hdr.code == CDN_TYPECHANGE)
-               CommDlg_OpenSave_SetControlText (dialog,
-                                                FILE_NAME_TEXT_FIELD,
-                                                 GUISTR (""));
+             if (hdr_code == CDN_TYPECHANGE)
+               {
+                 if (use_unicode)
+                   SendMessageW (dialog, CDM_SETCONTROLTEXT,
+                                 FILE_NAME_TEXT_FIELD, (LPARAM)L"");
+                 else
+                   SendMessageA (dialog, CDM_SETCONTROLTEXT,
+                                 FILE_NAME_TEXT_FIELD, (LPARAM)"");
+               }
              EnableWindow (edit_control, TRUE);
            }
        }
@@ -6374,8 +6407,8 @@
   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, 
Lisp_Object mustmatch, Lisp_Object only_dir_p)
 {
   /* Filter index: 1: All Files, 2: Directories only  */
-  static const guichar_t filter[] =
-    GUISTR ("All Files (*.*)\0*.*\0Directories\0*|*\0");
+  static const wchar_t filter_w[] = L"All Files 
(*.*)\0*.*\0Directories\0*|*\0";
+  static const char filter_a[] = "All Files (*.*)\0*.*\0Directories\0*|*\0";
 
   Lisp_Object filename = default_filename;
   struct frame *f = SELECTED_FRAME ();
@@ -6388,25 +6421,36 @@
      enough struct for the new dialog to trick GetOpenFileName into
      giving us the new dialogs on newer versions of Windows.  */
   struct {
-#ifdef NTGUI_UNICODE
     OPENFILENAMEW details;
-#else /* !NTGUI_UNICODE */
+#if _WIN32_WINNT < 0x500 /* < win2k */
+      PVOID pvReserved;
+      DWORD dwReserved;
+      DWORD FlagsEx;
+#endif /* < win2k */
+  } new_file_details_w;
+
+#ifdef NTGUI_UNICODE
+  wchar_t filename_buf_w[32*1024 + 1]; // NT kernel maximum
+  OPENFILENAMEW * file_details_w = &new_file_details_w.details;
+  const int use_unicode = 1;
+#else /* not NTGUI_UNICODE */
+  struct {
     OPENFILENAMEA details;
-#endif /* NTGUI_UNICODE */
-
 #if _WIN32_WINNT < 0x500 /* < win2k */
       PVOID pvReserved;
       DWORD dwReserved;
       DWORD FlagsEx;
 #endif /* < win2k */
-  } new_file_details;
-
-#ifdef NTGUI_UNICODE
-  wchar_t filename_buf[32*1024 + 1]; // NT kernel maximum
-  OPENFILENAMEW * file_details = &new_file_details.details;
-#else /* not NTGUI_UNICODE */
-  char filename_buf[MAX_PATH + 1];
-  OPENFILENAMEA * file_details = &new_file_details.details;
+  } new_file_details_a;
+  wchar_t filename_buf_w[MAX_PATH + 1], dir_w[MAX_PATH];
+  char filename_buf_a[MAX_PATH + 1], dir_a[MAX_PATH];
+  OPENFILENAMEW * file_details_w = &new_file_details_w.details;
+  OPENFILENAMEA * file_details_a = &new_file_details_a.details;
+  int use_unicode = w32_unicode_filenames;
+  wchar_t *prompt_w;
+  char *prompt_a;
+  int len;
+  char fname_ret[MAX_UTF8_PATH];
 #endif /* NTGUI_UNICODE */
 
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
@@ -6452,6 +6496,10 @@
     to_unicode (prompt, &prompt);
     to_unicode (dir, &dir);
     to_unicode (filename, &filename);
+    if (SBYTES (filename) + 1 > sizeof (filename_buf_w))
+      report_file_error ("filename too long", default_filename);
+
+    memcpy (filename_buf_w, SDATA (filename), SBYTES (filename) + 1);
 #else /* !NTGUI_UNICODE */
     prompt = ENCODE_FILE (prompt);
     dir = ENCODE_FILE (dir);
@@ -6462,6 +6510,49 @@
     unixtodos_filename (SDATA (dir));
     filename = Fcopy_sequence (filename);
     unixtodos_filename (SDATA (filename));
+    if (SBYTES (filename) >= MAX_UTF8_PATH)
+      report_file_error ("filename too long", default_filename);
+    if (w32_unicode_filenames)
+      {
+       filename_to_utf16 (SSDATA (dir), dir_w);
+       if (filename_to_utf16 (SSDATA (filename), filename_buf_w) != 0)
+         {
+           /* filename_to_utf16 sets errno to ENOENT when the file
+              name is too long or cannot be converted to UTF-16.  */
+           if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
+             report_file_error ("filename too long", default_filename);
+         }
+       len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+                                  SSDATA (prompt), -1, NULL, 0);
+       if (len > 32768)
+         len = 32768;
+       prompt_w = alloca (len * sizeof (wchar_t));
+       MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+                            SSDATA (prompt), -1, prompt_w, len);
+      }
+    else
+      {
+       filename_to_ansi (SSDATA (dir), dir_a);
+       if (filename_to_ansi (SSDATA (filename), filename_buf_a) != '\0')
+         {
+           /* filename_to_ansi sets errno to ENOENT when the file
+              name is too long or cannot be converted to UTF-16.  */
+           if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
+             report_file_error ("filename too long", default_filename);
+         }
+       len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+                                  SSDATA (prompt), -1, NULL, 0);
+       if (len > 32768)
+         len = 32768;
+       prompt_w = alloca (len * sizeof (wchar_t));
+       MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+                            SSDATA (prompt), -1, prompt_w, len);
+       len = WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, 
NULL);
+       if (len > 32768)
+         len = 32768;
+       prompt_a = alloca (len);
+       WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, prompt_a, len, NULL, 
NULL);
+      }
 #endif /* NTGUI_UNICODE */
 
     /* Fill in the structure for the call to GetOpenFileName below.
@@ -6470,48 +6561,88 @@
        builds, we tell the OS we're using an old version of the
        structure if the OS isn't new enough to support the newer
        version.  */
-    memset (&new_file_details, 0, sizeof (new_file_details));
-
-    if (w32_major_version > 4 && w32_major_version < 95)
-      file_details->lStructSize = sizeof (new_file_details);
+    if (use_unicode)
+      {
+       memset (&new_file_details_w, 0, sizeof (new_file_details_w));
+       if (w32_major_version > 4 && w32_major_version < 95)
+         file_details_w->lStructSize = sizeof (new_file_details_w);
+       else
+         file_details_w->lStructSize = sizeof (*file_details_w);
+       /* Set up the inout parameter for the selected file name.  */
+       file_details_w->lpstrFile = filename_buf_w;
+       file_details_w->nMaxFile =
+         sizeof (filename_buf_w) / sizeof (*filename_buf_w);
+       file_details_w->hwndOwner = FRAME_W32_WINDOW (f);
+       /* Undocumented Bug in Common File Dialog:
+          If a filter is not specified, shell links are not resolved.  */
+       file_details_w->lpstrFilter = filter_w;
+#ifdef NTGUI_UNICODE
+       file_details_w->lpstrInitialDir = (wchar_t*) SDATA (dir);
+       file_details_w->lpstrTitle = (guichar_t*) SDATA (prompt);
+#else
+       file_details_w->lpstrInitialDir = dir_w;
+       file_details_w->lpstrTitle = prompt_w;
+#endif
+       file_details_w->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
+       file_details_w->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
+                                | OFN_EXPLORER | OFN_ENABLEHOOK);
+       if (!NILP (mustmatch))
+         {
+           /* Require that the path to the parent directory exists.  */
+           file_details_w->Flags |= OFN_PATHMUSTEXIST;
+           /* If we are looking for a file, require that it exists.  */
+           if (NILP (only_dir_p))
+             file_details_w->Flags |= OFN_FILEMUSTEXIST;
+         }
+      }
+#ifndef NTGUI_UNICODE
     else
-      file_details->lStructSize = sizeof (*file_details);
-
-    /* Set up the inout parameter for the selected file name.  */
-    if (SBYTES (filename) + 1 > sizeof (filename_buf))
-      report_file_error ("filename too long", default_filename);
-
-    memcpy (filename_buf, SDATA (filename), SBYTES (filename) + 1);
-    file_details->lpstrFile = filename_buf;
-    file_details->nMaxFile = sizeof (filename_buf) / sizeof (*filename_buf);
-
-    file_details->hwndOwner = FRAME_W32_WINDOW (f);
-    /* Undocumented Bug in Common File Dialog:
-       If a filter is not specified, shell links are not resolved.  */
-    file_details->lpstrFilter = filter;
-    file_details->lpstrInitialDir = (guichar_t*) SDATA (dir);
-    file_details->lpstrTitle = (guichar_t*) SDATA (prompt);
-    file_details->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
-    file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
-                           | OFN_EXPLORER | OFN_ENABLEHOOK);
-
-    if (!NILP (mustmatch))
       {
-        /* Require that the path to the parent directory exists.  */
-        file_details->Flags |= OFN_PATHMUSTEXIST;
-        /* If we are looking for a file, require that it exists.  */
-        if (NILP (only_dir_p))
-          file_details->Flags |= OFN_FILEMUSTEXIST;
+       memset (&new_file_details_a, 0, sizeof (new_file_details_a));
+       if (w32_major_version > 4 && w32_major_version < 95)
+         file_details_a->lStructSize = sizeof (new_file_details_a);
+       else
+         file_details_a->lStructSize = sizeof (*file_details_a);
+       file_details_a->lpstrFile = filename_buf_a;
+       file_details_a->nMaxFile =
+         sizeof (filename_buf_a) / sizeof (*filename_buf_a);
+       file_details_a->hwndOwner = FRAME_W32_WINDOW (f);
+       file_details_a->lpstrFilter = filter_a;
+       file_details_a->lpstrInitialDir = dir_a;
+       file_details_a->lpstrTitle = prompt_a;
+       file_details_a->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
+       file_details_a->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
+                                | OFN_EXPLORER | OFN_ENABLEHOOK);
+       if (!NILP (mustmatch))
+         {
+           /* Require that the path to the parent directory exists.  */
+           file_details_a->Flags |= OFN_PATHMUSTEXIST;
+           /* If we are looking for a file, require that it exists.  */
+           if (NILP (only_dir_p))
+             file_details_a->Flags |= OFN_FILEMUSTEXIST;
+         }
       }
+#endif /* !NTGUI_UNICODE */
 
     {
       int count = SPECPDL_INDEX ();
       /* Prevent redisplay.  */
       specbind (Qinhibit_redisplay, Qt);
       block_input ();
-      file_details->lpfnHook = file_dialog_callback;
-
-      file_opened = GUI_FN (GetOpenFileName) (file_details);
+      if (use_unicode)
+       {
+         file_details_w->lpfnHook = file_dialog_callback;
+
+         file_opened = GetOpenFileNameW (file_details_w);
+       }
+#ifndef NTGUI_UNICODE
+      else
+       {
+         file_details_a->lpfnHook = file_dialog_callback;
+
+         file_opened = GetOpenFileNameA (file_details_a);
+       }
+#endif /* !NTGUI_UNICODE */
       unblock_input ();
       unbind_to (count, Qnil);
     }
@@ -6520,10 +6651,14 @@
       {
         /* Get an Emacs string from the value Windows gave us.  */
 #ifdef NTGUI_UNICODE
-        filename = from_unicode_buffer (filename_buf);
+        filename = from_unicode_buffer (filename_buf_w);
 #else /* !NTGUI_UNICODE */
-        dostounix_filename (filename_buf, 0);
-        filename = DECODE_FILE (build_string (filename_buf));
+       if (use_unicode)
+         filename_from_utf16 (filename_buf_w, fname_ret);
+       else
+         filename_from_ansi (filename_buf_a, fname_ret);
+       dostounix_filename (fname_ret);
+        filename = DECODE_FILE (build_unibyte_string (fname_ret));
 #endif /* NTGUI_UNICODE */
 
 #ifdef CYGWIN
@@ -6532,10 +6667,12 @@
 
         /* Strip the dummy filename off the end of the string if we
            added it to select a directory.  */
-        if (file_details->nFilterIndex == 2)
-          {
-            filename = Ffile_name_directory (filename);
-          }
+        if (use_unicode && file_details_w->nFilterIndex == 2
+#ifndef NTGUI_UNICODE
+           || !use_unicode && file_details_a->nFilterIndex == 2
+#endif
+           )
+         filename = Ffile_name_directory (filename);
       }
     /* User canceled the dialog without making a selection.  */
     else if (!CommDlgExtendedError ())
@@ -6582,38 +6719,80 @@
       operation = intern ("delete-directory");
       filename = Fdirectory_file_name (filename);
     }
+
+  /* Must have fully qualified file names for moving files to Recycle
+     Bin. */
   filename = Fexpand_file_name (filename, Qnil);
 
   handler = Ffind_file_name_handler (filename, operation);
   if (!NILP (handler))
     return call2 (handler, operation, filename);
-
-  encoded_file = ENCODE_FILE (filename);
-
-  {
-    const char * path;
-    SHFILEOPSTRUCT file_op;
-    char tmp_path[MAX_PATH + 1];
-
-    path = map_w32_filename (SDATA (encoded_file), NULL);
-
-    /* On Windows, write permission is required to delete/move files.  */
-    _chmod (path, 0666);
-
-    memset (tmp_path, 0, sizeof (tmp_path));
-    strcpy (tmp_path, path);
-
-    memset (&file_op, 0, sizeof (file_op));
-    file_op.hwnd = HWND_DESKTOP;
-    file_op.wFunc = FO_DELETE;
-    file_op.pFrom = tmp_path;
-    file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
-      | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
-    file_op.fAnyOperationsAborted = FALSE;
-
-    if (SHFileOperation (&file_op) != 0)
-      report_file_error ("Removing old name", list1 (filename));
-  }
+  else
+    {
+      const char * path;
+      int result;
+
+      encoded_file = ENCODE_FILE (filename);
+
+      path = map_w32_filename (SDATA (encoded_file), NULL);
+
+      /* The Unicode version of SHFileOperation is not supported on
+        Windows 9X. */
+      if (w32_unicode_filenames && os_subtype != OS_9X)
+       {
+         SHFILEOPSTRUCTW file_op_w;
+         /* We need one more element beyond MAX_PATH because this is
+            a list of file names, with the last element double-null
+            terminated. */
+         wchar_t tmp_path_w[MAX_PATH + 1];
+
+         memset (tmp_path_w, 0, sizeof (tmp_path_w));
+         filename_to_utf16 (path, tmp_path_w);
+
+         /* On Windows, write permission is required to delete/move files.  */
+         _wchmod (tmp_path_w, 0666);
+
+         memset (&file_op_w, 0, sizeof (file_op_w));
+         file_op_w.hwnd = HWND_DESKTOP;
+         file_op_w.wFunc = FO_DELETE;
+         file_op_w.pFrom = tmp_path_w;
+         file_op_w.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+           | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+         file_op_w.fAnyOperationsAborted = FALSE;
+
+         result = SHFileOperationW (&file_op_w);
+       }
+      else
+       {
+         SHFILEOPSTRUCTA file_op_a;
+         char tmp_path_a[MAX_PATH + 1];
+
+         memset (tmp_path_a, 0, sizeof (tmp_path_a));
+         filename_to_ansi (path, tmp_path_a);
+
+         /* If a file cannot be represented in ANSI codepage, don't
+            let them inadvertently delete other files because some
+            characters are interpreted as a wildcards.  */
+         if (_mbspbrk (tmp_path_a, "?*"))
+           result = ERROR_FILE_NOT_FOUND;
+         else
+           {
+             _chmod (tmp_path_a, 0666);
+
+             memset (&file_op_a, 0, sizeof (file_op_a));
+             file_op_a.hwnd = HWND_DESKTOP;
+             file_op_a.wFunc = FO_DELETE;
+             file_op_a.pFrom = tmp_path_a;
+             file_op_a.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
+               | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
+             file_op_a.fAnyOperationsAborted = FALSE;
+
+             result = SHFileOperationA (&file_op_a);
+           }
+       }
+      if (result != 0)
+       report_file_error ("Removing old name", list1 (filename));
+    }
   return Qnil;
 }
 
@@ -6688,38 +6867,159 @@
   6 - start minimized  */)
   (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, 
Lisp_Object show_flag)
 {
-  Lisp_Object current_dir;
   char *errstr;
+  Lisp_Object current_dir = BVAR (current_buffer, directory);;
+  wchar_t *doc_w = NULL, *params_w = NULL, *ops_w = NULL;
+  intptr_t result;
+#ifndef CYGWIN
+  int use_unicode = w32_unicode_filenames;
+  char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
+#endif
 
   CHECK_STRING (document);
 
-  /* Encode filename, current directory and parameters.  */
-  current_dir = BVAR (current_buffer, directory);
-
 #ifdef CYGWIN
   current_dir = Fcygwin_convert_file_name_to_windows (current_dir, Qt);
   if (STRINGP (document))
     document = Fcygwin_convert_file_name_to_windows (document, Qt);
-#endif /* CYGWIN */
 
+  /* Encode filename, current directory and parameters.  */
   current_dir = GUI_ENCODE_FILE (current_dir);
   if (STRINGP (document))
-    document = GUI_ENCODE_FILE (document);
+    {
+      document = GUI_ENCODE_FILE (document);
+      doc_w = GUI_SDATA (document);
+    }
   if (STRINGP (parameters))
-    parameters = GUI_ENCODE_SYSTEM (parameters);
-
-  if ((int) GUI_FN (ShellExecute) (NULL,
-                                   (STRINGP (operation) ?
-                                    GUI_SDATA (operation) : NULL),
-                                   GUI_SDATA (document),
-                                   (STRINGP (parameters) ?
-                                    GUI_SDATA (parameters) : NULL),
-                                   GUI_SDATA (current_dir),
-                                   (INTEGERP (show_flag) ?
-                                    XINT (show_flag) : SW_SHOWDEFAULT))
-      > 32)
+    {
+      parameters = GUI_ENCODE_SYSTEM (parameters);
+      params_w = GUI_SDATA (parameters);
+    }
+  if (STRINGP (operation))
+    {
+      operation = GUI_ENCODE_SYSTEM (operation);
+      ops_w = GUI_SDATA (operation);
+    }
+  result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
+                                    GUI_SDATA (current_dir),
+                                    (INTEGERP (show_flag)
+                                     ? XINT (show_flag) : SW_SHOWDEFAULT));
+#else  /* !CYGWIN */
+  if (use_unicode)
+    {
+      wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
+
+      /* Encode filename, current directory and parameters, and
+        convert operation to UTF-16.  */
+      current_dir = ENCODE_FILE (current_dir);
+      filename_to_utf16 (SSDATA (current_dir), current_dir_w);
+      if (STRINGP (document))
+       {
+         document = ENCODE_FILE (document);
+         filename_to_utf16 (SSDATA (document), document_w);
+         doc_w = document_w;
+       }
+      if (STRINGP (parameters))
+       {
+         int len;
+
+         parameters = ENCODE_SYSTEM (parameters);
+         len = MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+                                    SSDATA (parameters), -1, NULL, 0);
+         if (len > 32768)
+           len = 32768;
+         params_w = alloca (len * sizeof (wchar_t));
+         MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+                              SSDATA (parameters), -1, params_w, len);
+       }
+      if (STRINGP (operation))
+       {
+         /* Assume OPERATION is pure ASCII.  */
+         const char *s = SSDATA (operation);
+         wchar_t *d;
+         int len = SBYTES (operation) + 1;
+
+         if (len > 32768)
+           len = 32768;
+         d = ops_w = alloca (len * sizeof (wchar_t));
+         while (d < ops_w + len - 1)
+           *d++ = *s++;
+         *d = 0;
+       }
+      result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
+                                        current_dir_w,
+                                        (INTEGERP (show_flag)
+                                         ? XINT (show_flag) : SW_SHOWDEFAULT));
+    }
+  else
+    {
+      char document_a[MAX_PATH], current_dir_a[MAX_PATH];
+
+      current_dir = ENCODE_FILE (current_dir);
+      filename_to_ansi (SSDATA (current_dir), current_dir_a);
+      if (STRINGP (document))
+       {
+         ENCODE_FILE (document);
+         filename_to_ansi (SSDATA (document), document_a);
+         doc_a = document_a;
+       }
+      if (STRINGP (parameters))
+       {
+         int len;
+
+         parameters = ENCODE_SYSTEM (parameters);
+         params_a = SSDATA (parameters);
+       }
+      if (STRINGP (operation))
+       {
+         /* Assume OPERATION is pure ASCII.  */
+         ops_a = SSDATA (operation);
+       }
+      result = (intptr_t) ShellExecuteA (NULL, ops_a, doc_a, params_a,
+                                        current_dir_a,
+                                        (INTEGERP (show_flag)
+                                         ? XINT (show_flag) : SW_SHOWDEFAULT));
+    }
+#endif /* !CYGWIN */
+
+  if (result > 32)
     return Qt;
-  errstr = w32_strerror (0);
+
+  switch (result)
+    {
+    case SE_ERR_ACCESSDENIED:
+      errstr = w32_strerror (ERROR_ACCESS_DENIED);
+      break;
+    case SE_ERR_ASSOCINCOMPLETE:
+    case SE_ERR_NOASSOC:
+      errstr = w32_strerror (ERROR_NO_ASSOCIATION);
+      break;
+    case SE_ERR_DDEBUSY:
+    case SE_ERR_DDEFAIL:
+      errstr = w32_strerror (ERROR_DDE_FAIL);
+      break;
+    case SE_ERR_DDETIMEOUT:
+      errstr = w32_strerror (ERROR_TIMEOUT);
+      break;
+    case SE_ERR_DLLNOTFOUND:
+      errstr = w32_strerror (ERROR_DLL_NOT_FOUND);
+      break;
+    case SE_ERR_FNF:
+      errstr = w32_strerror (ERROR_FILE_NOT_FOUND);
+      break;
+    case SE_ERR_OOM:
+      errstr = w32_strerror (ERROR_NOT_ENOUGH_MEMORY);
+      break;
+    case SE_ERR_PNF:
+      errstr = w32_strerror (ERROR_PATH_NOT_FOUND);
+      break;
+    case SE_ERR_SHARE:
+      errstr = w32_strerror (ERROR_SHARING_VIOLATION);
+      break;
+    default:
+      errstr = w32_strerror (0);
+      break;
+    }
   /* The error string might be encoded in the locale's encoding.  */
   if (!NILP (Vlocale_coding_system))
     {
@@ -7132,14 +7432,23 @@
      added rather late on.  */
   {
     HMODULE hKernel = GetModuleHandle ("kernel32");
-    BOOL (*pfn_GetDiskFreeSpaceEx)
+    BOOL (*pfn_GetDiskFreeSpaceExW)
+      (wchar_t *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
+      = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExW");
+    BOOL (*pfn_GetDiskFreeSpaceExA)
       (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
-      = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
+      = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExA");
+    bool have_pfn_GetDiskFreeSpaceEx =
+      (w32_unicode_filenames && pfn_GetDiskFreeSpaceExW
+       || !w32_unicode_filenames && pfn_GetDiskFreeSpaceExA);
 
     /* On Windows, we may need to specify the root directory of the
        volume holding FILENAME.  */
-    char rootname[MAX_PATH];
+    char rootname[MAX_UTF8_PATH];
+    wchar_t rootname_w[MAX_PATH];
+    char rootname_a[MAX_PATH];
     char *name = SDATA (encoded);
+    BOOL result;
 
     /* find the root name of the volume if given */
     if (isalpha (name[0]) && name[1] == ':')
@@ -7165,7 +7474,12 @@
        *str = 0;
       }
 
-    if (pfn_GetDiskFreeSpaceEx)
+    if (w32_unicode_filenames)
+      filename_to_utf16 (rootname, rootname_w);
+    else
+      filename_to_ansi (rootname, rootname_a);
+
+    if (have_pfn_GetDiskFreeSpaceEx)
       {
        /* Unsigned large integers cannot be cast to double, so
           use signed ones instead.  */
@@ -7173,10 +7487,17 @@
        LARGE_INTEGER freebytes;
        LARGE_INTEGER totalbytes;
 
-       if (pfn_GetDiskFreeSpaceEx (rootname,
-                                   (ULARGE_INTEGER *)&availbytes,
-                                   (ULARGE_INTEGER *)&totalbytes,
-                                   (ULARGE_INTEGER *)&freebytes))
+       if (w32_unicode_filenames)
+         result = pfn_GetDiskFreeSpaceExW (rootname_w,
+                                           (ULARGE_INTEGER *)&availbytes,
+                                           (ULARGE_INTEGER *)&totalbytes,
+                                           (ULARGE_INTEGER *)&freebytes);
+       else
+         result = pfn_GetDiskFreeSpaceExA (rootname_a,
+                                           (ULARGE_INTEGER *)&availbytes,
+                                           (ULARGE_INTEGER *)&totalbytes,
+                                           (ULARGE_INTEGER *)&freebytes);
+       if (result)
          value = list3 (make_float ((double) totalbytes.QuadPart),
                         make_float ((double) freebytes.QuadPart),
                         make_float ((double) availbytes.QuadPart));
@@ -7188,11 +7509,19 @@
        DWORD free_clusters;
        DWORD total_clusters;
 
-       if (GetDiskFreeSpace (rootname,
-                             &sectors_per_cluster,
-                             &bytes_per_sector,
-                             &free_clusters,
-                             &total_clusters))
+       if (w32_unicode_filenames)
+         result = GetDiskFreeSpaceW (rootname_w,
+                                     &sectors_per_cluster,
+                                     &bytes_per_sector,
+                                     &free_clusters,
+                                     &total_clusters);
+       else
+         result = GetDiskFreeSpaceA (rootname_a,
+                                     &sectors_per_cluster,
+                                     &bytes_per_sector,
+                                     &free_clusters,
+                                     &total_clusters);
+       if (result)
          value = list3 (make_float ((double) total_clusters
                                     * sectors_per_cluster * bytes_per_sector),
                         make_float ((double) free_clusters
@@ -7207,6 +7536,7 @@
 #endif /* WINDOWSNT */
 
 
+#ifdef WINDOWSNT
 DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
        0, 0, 0, doc: /* Return the name of Windows default printer device.  */)
   (void)
@@ -7214,8 +7544,11 @@
   static char pname_buf[256];
   int err;
   HANDLE hPrn;
-  PRINTER_INFO_2 *ppi2 = NULL;
+  PRINTER_INFO_2W *ppi2w = NULL;
+  PRINTER_INFO_2A *ppi2a = NULL;
   DWORD dwNeeded = 0, dwReturned = 0;
+  char server_name[MAX_UTF8_PATH], share_name[MAX_UTF8_PATH];
+  char port_name[MAX_UTF8_PATH];
 
   /* Retrieve the default string from Win.ini (the registry).
    * String will be in form "printername,drivername,portname".
@@ -7227,55 +7560,89 @@
   /* We want to know more than the printer name */
   if (!OpenPrinter (pname_buf, &hPrn, NULL))
     return Qnil;
-  GetPrinter (hPrn, 2, NULL, 0, &dwNeeded);
+  /* GetPrinterW is not supported by unicows.dll.  */
+  if (w32_unicode_filenames && os_subtype != OS_9X)
+    GetPrinterW (hPrn, 2, NULL, 0, &dwNeeded);
+  else
+    GetPrinterA (hPrn, 2, NULL, 0, &dwNeeded);
   if (dwNeeded == 0)
     {
       ClosePrinter (hPrn);
       return Qnil;
     }
-  /* Allocate memory for the PRINTER_INFO_2 struct */
-  ppi2 = xmalloc (dwNeeded);
-  if (!ppi2)
-    {
-      ClosePrinter (hPrn);
-      return Qnil;
-    }
   /* Call GetPrinter again with big enough memory block.  */
-  err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
-  ClosePrinter (hPrn);
-  if (!err)
-    {
-      xfree (ppi2);
-      return Qnil;
-    }
-
-  if (ppi2)
-    {
-      if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName)
-        {
-         /* a remote printer */
-         if (*ppi2->pServerName == '\\')
-           snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", 
ppi2->pServerName,
-                      ppi2->pShareName);
-         else
-           snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", 
ppi2->pServerName,
-                      ppi2->pShareName);
-         pname_buf[sizeof (pname_buf) - 1] = '\0';
-       }
-      else
-        {
-         /* a local printer */
-         strncpy (pname_buf, ppi2->pPortName, sizeof (pname_buf));
-         pname_buf[sizeof (pname_buf) - 1] = '\0';
-         /* `pPortName' can include several ports, delimited by ','.
-          * we only use the first one. */
-         strtok (pname_buf, ",");
-       }
-      xfree (ppi2);
-    }
-
-  return build_string (pname_buf);
+  if (w32_unicode_filenames && os_subtype != OS_9X)
+    {
+      /* Allocate memory for the PRINTER_INFO_2 struct.  */
+      ppi2w = xmalloc (dwNeeded);
+      err = GetPrinterW (hPrn, 2, (LPBYTE)ppi2w, dwNeeded, &dwReturned);
+      ClosePrinter (hPrn);
+      if (!err)
+       {
+         xfree (ppi2w);
+         return Qnil;
+       }
+
+      if ((ppi2w->Attributes & PRINTER_ATTRIBUTE_SHARED)
+         && ppi2w->pServerName)
+       {
+         filename_from_utf16 (ppi2w->pServerName, server_name);
+         filename_from_utf16 (ppi2w->pShareName, share_name);
+       }
+      else
+       {
+         server_name[0] = '\0';
+         filename_from_utf16 (ppi2w->pPortName, port_name);
+       }
+    }
+  else
+    {
+      ppi2a = xmalloc (dwNeeded);
+      err = GetPrinterA (hPrn, 2, (LPBYTE)ppi2a, dwNeeded, &dwReturned);
+      ClosePrinter (hPrn);
+      if (!err)
+       {
+         xfree (ppi2a);
+         return Qnil;
+       }
+
+      if ((ppi2a->Attributes & PRINTER_ATTRIBUTE_SHARED)
+         && ppi2a->pServerName)
+       {
+         filename_from_ansi (ppi2a->pServerName, server_name);
+         filename_from_ansi (ppi2a->pShareName, share_name);
+       }
+      else
+       {
+         server_name[0] = '\0';
+         filename_from_ansi (ppi2a->pPortName, port_name);
+       }
+    }
+
+  if (server_name[0])
+    {
+      /* a remote printer */
+      if (server_name[0] == '\\')
+       snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", server_name,
+                 share_name);
+      else
+       snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", server_name,
+                 share_name);
+      pname_buf[sizeof (pname_buf) - 1] = '\0';
+    }
+  else
+    {
+      /* a local printer */
+      strncpy (pname_buf, port_name, sizeof (pname_buf));
+      pname_buf[sizeof (pname_buf) - 1] = '\0';
+      /* `pPortName' can include several ports, delimited by ','.
+       * we only use the first one. */
+      strtok (pname_buf, ",");
+    }
+
+  return DECODE_FILE (build_unibyte_string (pname_buf));
 }
+#endif /* WINDOWSNT */
 
 
 /* Equivalent of strerror for W32 error codes.  */
@@ -7946,9 +8313,9 @@
 
 #ifdef WINDOWSNT
   defsubr (&Sfile_system_info);
-#endif
-
   defsubr (&Sdefault_printer_name);
+#endif
+
   defsubr (&Sset_message_beep);
 
   hourglass_hwnd = NULL;

=== modified file 'src/w32notify.c'
--- a/src/w32notify.c   2013-11-28 19:40:15 +0000
+++ b/src/w32notify.c   2013-12-08 18:29:12 +0000
@@ -105,7 +105,7 @@
   OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
   BOOL subtree;                /* whether to watch subdirectories */
   DWORD filter;                /* bit mask for events to watch */
-  char *watchee;       /* the file we are interested in */
+  char *watchee;       /* the file we are interested in, UTF-8 encoded */
   HANDLE dir;          /* handle to the watched directory */
   HANDLE thr;          /* handle to the thread that watches */
   volatile int terminate; /* if non-zero, request for the thread to terminate 
*/
@@ -332,15 +332,43 @@
   if (!file)
     return NULL;
 
-  hdir = CreateFile (parent_dir,
-                    FILE_LIST_DIRECTORY,
-                    /* FILE_SHARE_DELETE doesn't preclude other
-                       processes from deleting files inside
-                       parent_dir.  */
-                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                    NULL, OPEN_EXISTING,
-                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
-                    NULL);
+  if (w32_unicode_filenames)
+    {
+      wchar_t dir_w[MAX_PATH], file_w[MAX_PATH];
+
+      filename_to_utf16 (parent_dir, dir_w);
+      if (*file)
+       filename_to_utf16 (file, file_w);
+      else
+       file_w[0] = 0;
+
+      hdir = CreateFileW (dir_w,
+                         FILE_LIST_DIRECTORY,
+                         /* FILE_SHARE_DELETE doesn't preclude other
+                            processes from deleting files inside
+                            parent_dir.  */
+                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                         NULL, OPEN_EXISTING,
+                         FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+                         NULL);
+    }
+  else
+    {
+      char dir_a[MAX_PATH], file_a[MAX_PATH];
+
+      filename_to_ansi (parent_dir, dir_a);
+      if (*file)
+       filename_to_ansi (file, file_a);
+      else
+       file_a[0] = '\0';
+
+      hdir = CreateFileA (dir_a,
+                         FILE_LIST_DIRECTORY,
+                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                         NULL, OPEN_EXISTING,
+                         FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+                         NULL);
+    }
   if (hdir == INVALID_HANDLE_VALUE)
     return NULL;
 
@@ -490,9 +518,7 @@
 generate notifications correctly, though.  */)
   (Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
 {
-  Lisp_Object encoded_file, watch_object, watch_descriptor;
-  char parent_dir[MAX_PATH], *basename;
-  size_t fn_len;
+  Lisp_Object dirfn, basefn, watch_object, watch_descriptor;
   DWORD flags;
   BOOL subdirs = FALSE;
   struct notification *dirwatch = NULL;
@@ -510,49 +536,33 @@
                         Qnil);
     }
 
-  /* We need a full absolute file name of FILE, and we need to remove
-     any trailing slashes from it, so that GetFullPathName below gets
-     the basename part correctly.  */
-  file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
-  encoded_file = ENCODE_FILE (file);
-
-  fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir,
-                           &basename);
-  if (!fn_len)
-    {
-      errstr = w32_strerror (0);
-      errno = EINVAL;
-      if (!NILP (Vlocale_coding_system))
-       lisp_errstr
-         = code_convert_string_norecord (build_unibyte_string (errstr),
-                                         Vlocale_coding_system, 0);
-      else
-       lisp_errstr = build_string (errstr);
-      report_file_error ("GetFullPathName failed",
-                        Fcons (lisp_errstr, Fcons (file, Qnil)));
-    }
   /* filenotify.el always passes us a directory, either the parent
      directory of a file to be watched, or the directory to be
      watched.  */
-  if (file_directory_p (parent_dir))
-    basename = "";
-  else
+  file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
+  if (NILP (Ffile_directory_p (file)))
     {
       /* This should only happen if we are called directly, not via
-        filenotify.el.  If BASENAME is NULL, the argument was the
-        root directory on its drive.  */
-      if (basename)
-       basename[-1] = '\0';
-      else
+        filenotify.el.  If BASEFN is empty, the argument was the root
+        directory on its drive.  */
+      dirfn = ENCODE_FILE (Ffile_name_directory (file));
+      basefn = ENCODE_FILE (Ffile_name_nondirectory (file));
+      if (*SDATA (basefn) == '\0')
        subdirs = TRUE;
     }
+  else
+    {
+      dirfn = ENCODE_FILE (file);
+      basefn = Qnil;
+    }
 
   if (!NILP (Fmember (Qsubtree, filter)))
     subdirs = TRUE;
 
   flags = filter_list_to_flags (filter);
 
-  dirwatch = add_watch (parent_dir, basename, subdirs, flags);
+  dirwatch = add_watch (SSDATA (dirfn), NILP (basefn) ? "" : SSDATA (basefn),
+                       subdirs, flags);
   if (!dirwatch)
     {
       DWORD err = GetLastError ();

=== modified file 'src/w32proc.c'
--- a/src/w32proc.c     2013-11-28 19:40:15 +0000
+++ b/src/w32proc.c     2013-12-07 17:21:57 +0000
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <sys/file.h>
+#include <mbstring.h>
 
 /* must include CRT headers *before* config.h */
 #include <config.h>
@@ -861,8 +862,6 @@
   cp->pid = -1;
   cp->procinfo.hProcess = NULL;
   cp->status = STATUS_READ_ERROR;
-  cp->input_file = NULL;
-  cp->pending_deletion = 0;
 
   /* use manual reset event so that select() will function properly */
   cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
@@ -911,21 +910,6 @@
   if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
     return;
 
-  /* Delete the child's temporary input file, if any, that is pending
-     deletion.  */
-  if (cp->input_file)
-    {
-      if (cp->pending_deletion)
-       {
-         if (unlink (cp->input_file))
-           DebPrint (("delete_child.unlink (%s) failed, errno: %d\n",
-                      cp->input_file, errno));
-         cp->pending_deletion = 0;
-       }
-      xfree (cp->input_file);
-      cp->input_file = NULL;
-    }
-
   /* reap thread if necessary */
   if (cp->thrd)
     {
@@ -1073,9 +1057,10 @@
   return 0;
 }
 
-/* To avoid Emacs changing directory, we just record here the directory
-   the new process should start in.  This is set just before calling
-   sys_spawnve, and is not generally valid at any other time.  */
+/* To avoid Emacs changing directory, we just record here the
+   directory the new process should start in.  This is set just before
+   calling sys_spawnve, and is not generally valid at any other time.
+   Note that this directory's name is UTF-8 encoded.  */
 static char * process_dir;
 
 static BOOL
@@ -1088,7 +1073,8 @@
   SECURITY_DESCRIPTOR sec_desc;
 #endif
   DWORD flags;
-  char dir[ MAXPATHLEN ];
+  char dir[ MAX_PATH ];
+  char *p;
 
   if (cp == NULL) emacs_abort ();
 
@@ -1118,16 +1104,22 @@
   sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
   sec_attrs.bInheritHandle = FALSE;
 
-  strcpy (dir, process_dir);
-  unixtodos_filename (dir);
+  filename_to_ansi (process_dir, dir);
+  /* Can't use unixtodos_filename here, since that needs its file name
+     argument encoded in UTF-8.  OTOH, process_dir, which _is_ in
+     UTF-8, points, to the directory computed by our caller, and we
+     don't want to modify that, either.  */
+  for (p = dir; *p; p = CharNextA (p))
+    if (*p == '/')
+      *p = '\\';
 
   flags = (!NILP (Vw32_start_process_share_console)
           ? CREATE_NEW_PROCESS_GROUP
           : CREATE_NEW_CONSOLE);
   if (NILP (Vw32_start_process_inherit_error_mode))
     flags |= CREATE_DEFAULT_ERROR_MODE;
-  if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
-                     flags, env, dir, &start, &cp->procinfo))
+  if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
+                      flags, env, dir, &start, &cp->procinfo))
     goto EH_Fail;
 
   cp->pid = (int) cp->procinfo.dwProcessId;
@@ -1182,45 +1174,6 @@
   fd_info[fd].cp = cp;
 }
 
-/* Record INFILE as an input file for process PID.  */
-void
-record_infile (pid_t pid, char *infile)
-{
-  child_process *cp;
-
-  /* INFILE should never be NULL, since xstrdup would have signaled
-     memory full condition in that case, see callproc.c where this
-     function is called.  */
-  eassert (infile);
-
-  cp = find_child_pid ((DWORD)pid);
-  if (cp == NULL)
-    {
-      DebPrint (("record_infile is unable to find pid %lu\n", pid));
-      return;
-    }
-
-  cp->input_file = infile;
-}
-
-/* Mark the input file INFILE of the corresponding subprocess as
-   temporary, to be deleted when the subprocess exits.  */
-void
-record_pending_deletion (char *infile)
-{
-  child_process *cp;
-
-  eassert (infile);
-
-  for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
-    if (CHILD_ACTIVE (cp)
-       && cp->input_file && xstrcasecmp (cp->input_file, infile) == 0)
-      {
-       cp->pending_deletion = 1;
-       break;
-      }
-}
-
 /* Called from waitpid when a process exits.  */
 static void
 reap_subprocess (child_process *cp)
@@ -1427,6 +1380,8 @@
 # define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
 #endif
 
+/* Implementation note: This function works with file names encoded in
+   the current ANSI codepage.  */
 static void
 w32_executable_type (char * filename,
                     int * is_dos_app,
@@ -1617,6 +1572,7 @@
   char *sepchars = " \t*?";
   /* This is for native w32 apps; modified below for Cygwin apps.  */
   char escape_char = '\\';
+  char cmdname_a[MAX_PATH];
 
   /* We don't care about the other modes */
   if (mode != _P_NOWAIT)
@@ -1625,12 +1581,15 @@
       return -1;
     }
 
-  /* Handle executable names without an executable suffix.  */
-  program = build_string (cmdname);
-  if (NILP (Ffile_executable_p (program)))
+  /* Handle executable names without an executable suffix.  The caller
+     already searched exec-path and verified the file is executable,
+     but start-process doesn't do that for file names that are already
+     absolute.  So we double-check this here, just in case.  */
+  if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0)
     {
       struct gcpro gcpro1;
 
+      program = build_string (cmdname);
       full = Qnil;
       GCPRO1 (program);
       openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK));
@@ -1640,12 +1599,27 @@
          errno = EINVAL;
          return -1;
        }
-      program = full;
+      program = ENCODE_FILE (full);
+      cmdname = SDATA (program);
     }
 
   /* make sure argv[0] and cmdname are both in DOS format */
-  cmdname = SDATA (program);
   unixtodos_filename (cmdname);
+  /* argv[0] was encoded by caller using ENCODE_FILE, so it is in
+     UTF-8.  All the other arguments are encoded by ENCODE_SYSTEM or
+     some such, and are in some ANSI codepage.  We need to have
+     argv[0] encoded in ANSI codepage.  */
+  filename_to_ansi (cmdname, cmdname_a);
+  /* We explicitly require that the command's file name be encodable
+     in the current ANSI codepage, because we will be invoking it via
+     the ANSI APIs.  */
+  if (_mbspbrk (cmdname_a, "?"))
+    {
+      errno = ENOENT;
+      return -1;
+    }
+  /* From here on, CMDNAME is an ANSI-encoded string.  */
+  cmdname = cmdname_a;
   argv[0] = cmdname;
 
   /* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
@@ -1663,7 +1637,9 @@
      while leaving the real app name as argv[0].  */
   if (is_dos_app)
     {
-      cmdname = alloca (MAXPATHLEN);
+      char *p;
+
+      cmdname = alloca (MAX_PATH);
       if (egetenv ("CMDPROXY"))
        strcpy (cmdname, egetenv ("CMDPROXY"));
       else
@@ -1671,7 +1647,12 @@
          strcpy (cmdname, SDATA (Vinvocation_directory));
          strcat (cmdname, "cmdproxy.exe");
        }
-      unixtodos_filename (cmdname);
+
+      /* Can't use unixtodos_filename here, since that needs its file
+        name argument encoded in UTF-8.  */
+      for (p = cmdname; *p; p = CharNextA (p))
+       if (*p == '/')
+         *p = '\\';
     }
 
   /* we have to do some conjuring here to put argv and envp into the
@@ -2673,10 +2654,11 @@
   filename = Fexpand_file_name (filename, Qnil);
 
   /* luckily, this returns the short version of each element in the path.  */
-  if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) 
== 0)
+  if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)),
+                             shortname, MAX_PATH) == 0)
     return Qnil;
 
-  dostounix_filename (shortname, 0);
+  dostounix_filename (shortname);
 
   /* No need to DECODE_FILE, because 8.3 names are pure ASCII.   */
   return build_string (shortname);
@@ -2690,7 +2672,7 @@
 All path elements in FILENAME are converted to their long names.  */)
   (Lisp_Object filename)
 {
-  char longname[ MAX_PATH ];
+  char longname[ MAX_UTF8_PATH ];
   int drive_only = 0;
 
   CHECK_STRING (filename);
@@ -2702,10 +2684,11 @@
   /* first expand it.  */
   filename = Fexpand_file_name (filename, Qnil);
 
-  if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, 
MAX_PATH))
+  if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname,
+                             MAX_UTF8_PATH))
     return Qnil;
 
-  dostounix_filename (longname, 0);
+  dostounix_filename (longname);
 
   /* If we were passed only a drive, make sure that a slash is not appended
      for consistency with directories.  Allow for drive mapping via SUBST
@@ -2713,7 +2696,7 @@
   if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
     longname[2] = '\0';
 
-  return DECODE_FILE (build_string (longname));
+  return DECODE_FILE (build_unibyte_string (longname));
 }
 
 DEFUN ("w32-set-process-priority", Fw32_set_process_priority,

=== modified file 'src/w32term.c'
--- a/src/w32term.c     2013-12-11 15:06:04 +0000
+++ b/src/w32term.c     2013-12-11 17:06:29 +0000
@@ -52,6 +52,7 @@
 #include "keymap.h"
 
 #ifdef WINDOWSNT
+#include "w32.h"       /* for filename_from_utf16, filename_from_ansi */
 #include "w32heap.h"
 #endif
 
@@ -3128,7 +3129,14 @@
   HDROP hdrop;
   POINT p;
   WORD num_files;
-  guichar_t *name;
+  wchar_t name_w[MAX_PATH];
+#ifdef NTGUI_UNICODE
+  const int use_unicode = 1;
+#else
+  int use_unicode = w32_unicode_filenames;
+  char name_a[MAX_PATH];
+  char file[MAX_UTF8_PATH];
+#endif
   int i, len;
 
   result->kind = DRAG_N_DROP_EVENT;
@@ -3153,17 +3161,30 @@
 
   for (i = 0; i < num_files; i++)
     {
-      len = GUI_FN (DragQueryFile) (hdrop, i, NULL, 0);
-      if (len <= 0)
-       continue;
-
-      name = alloca ((len + 1) * sizeof (*name));
-      GUI_FN (DragQueryFile) (hdrop, i, name, len + 1);
+      if (use_unicode)
+       {
+         eassert (DragQueryFileW (hdrop, i, NULL, 0) < MAX_PATH);
+         /* If DragQueryFile returns zero, it failed to fetch a file
+            name.  */
+         if (DragQueryFileW (hdrop, i, name_w, MAX_PATH) == 0)
+           continue;
 #ifdef NTGUI_UNICODE
-      files = Fcons (from_unicode_buffer (name), files);
+         files = Fcons (from_unicode_buffer (name_w), files);
 #else
-      files = Fcons (DECODE_FILE (build_string (name)), files);
+         filename_from_utf16 (name_w, file);
+         files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
 #endif /* NTGUI_UNICODE */
+       }
+#ifndef NTGUI_UNICODE
+      else
+       {
+         eassert (DragQueryFileA (hdrop, i, NULL, 0) < MAX_PATH);
+         if (DragQueryFileA (hdrop, i, name_a, MAX_PATH) == 0)
+           continue;
+         filename_from_ansi (name_a, file);
+         files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
+       }
+#endif
     }
 
   DragFinish (hdrop);
@@ -6640,6 +6661,18 @@
 With MS Windows or Nextstep, the value is t.  */);
   Vx_toolkit_scroll_bars = Qt;
 
+  DEFVAR_BOOL ("w32-unicode-filenames",
+              w32_unicode_filenames,
+     doc: /* Non-nil means use Unicode APIs when passing file names to the OS.
+A value of nil means file names passed to the OS APIs and returned
+from those APIs are encoded/decoded using the ANSI codepage
+specified by `file-name-coding-system'.
+
+This variable is set to non-nil by default when Emacs runs on Windows
+systems of the NT family, including W2K, XP, Vista, Windows 7 and
+Windows 8.  It is set to nil on Windows 9X.  */);
+  w32_unicode_filenames = 0;
+
   /* Tell Emacs about this window system.  */
   Fprovide (Qw32, Qnil);
 }


reply via email to

[Prev in Thread] Current Thread [Next in Thread]