root/src/w32.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_windows_9x
  2. w32_get_internal_run_time
  3. open_process_token
  4. get_token_information
  5. lookup_account_sid
  6. get_sid_sub_authority
  7. get_sid_sub_authority_count
  8. get_security_info
  9. get_file_security
  10. set_file_security
  11. set_named_security_info
  12. get_security_descriptor_owner
  13. get_security_descriptor_group
  14. get_security_descriptor_dacl
  15. is_valid_sid
  16. equal_sid
  17. get_length_sid
  18. copy_sid
  19. get_native_system_info
  20. get_system_times
  21. create_symbolic_link
  22. is_valid_security_descriptor
  23. convert_sd_to_sddl
  24. convert_sddl_to_sd
  25. get_adapters_info
  26. get_adapters_addresses
  27. reg_open_key_ex_w
  28. reg_query_value_ex_w
  29. expand_environment_strings_w
  30. get_user_default_ui_language
  31. w32_valid_pointer_p
  32. w32_init_file_name_codepage
  33. codepage_for_filenames
  34. filename_to_utf16
  35. filename_from_utf16
  36. filename_to_ansi
  37. filename_from_ansi
  38. w32_get_current_directory
  39. w32_init_current_directory
  40. getcwd
  41. buf_next
  42. buf_prev
  43. w32_get_nproc
  44. num_processors
  45. sample_system_load
  46. getavg
  47. getloadavg
  48. getuid
  49. geteuid
  50. getgid
  51. getegid
  52. getpwuid
  53. getgrgid
  54. getpwnam
  55. init_user_info
  56. w32_init_crypt_random
  57. w32_init_random
  58. rand_as183
  59. random
  60. srandom
  61. explicit_bzero
  62. max_filename_mbslen
  63. normalize_filename
  64. dostounix_filename
  65. unixtodos_filename
  66. crlf_to_lf
  67. parse_root
  68. get_long_basename
  69. w32_get_long_filename
  70. w32_get_short_filename
  71. ansi_encode_filename
  72. is_unc_volume
  73. unsetenv
  74. sys_putenv
  75. init_environment
  76. emacs_root_dir
  77. fdutimens
  78. sys_ctime
  79. sys_sleep
  80. lookup_volume_info
  81. add_volume_info
  82. GetCachedVolumeInformation
  83. get_volume_info
  84. is_fat_volume
  85. map_w32_filename
  86. is_exec
  87. sys_opendir
  88. sys_closedir
  89. sys_readdir
  90. open_unc_volume
  91. read_unc_volume
  92. close_unc_volume
  93. unc_volume_file_attributes
  94. logon_network_drive
  95. faccessat
  96. w32_accessible_directory_p
  97. sys_access
  98. sys_chdir
  99. chmod_worker
  100. sys_chmod
  101. lchmod
  102. sys_creat
  103. sys_fopen
  104. sys_link
  105. sys_mkdir
  106. sys_open
  107. openat
  108. fchmod
  109. fchmodat
  110. sys_rename_replace
  111. sys_rename
  112. sys_rmdir
  113. sys_unlink
  114. initialize_utc_base
  115. convert_time
  116. convert_from_timespec
  117. get_file_security_desc_by_handle
  118. get_file_security_desc_by_name
  119. get_rid
  120. w32_cached_id
  121. w32_add_to_cache
  122. get_name_and_id
  123. get_file_owner_and_group
  124. is_slow_fs
  125. stat_worker
  126. stat
  127. lstat
  128. fstatat
  129. fstat
  130. utimensat
  131. sys_umask
  132. symlink
  133. is_symlink
  134. readlink
  135. readlinkat
  136. chase_symlinks
  137. symlinks_supported
  138. acl_valid
  139. acl_to_text
  140. acl_from_text
  141. acl_free
  142. acl_get_file
  143. acl_set_file
  144. acl_errno_valid
  145. careadlinkat
  146. w32_copy_file
  147. create_toolhelp32_snapshot
  148. process32_first
  149. process32_next
  150. open_thread_token
  151. impersonate_self
  152. revert_to_self
  153. get_process_memory_info
  154. get_process_working_set_size
  155. global_memory_status
  156. global_memory_status_ex
  157. list_system_processes
  158. enable_privilege
  159. restore_privilege
  160. ltime
  161. process_times
  162. system_process_attributes
  163. w32_memory_info
  164. term_winsock
  165. init_winsock
  166. set_errno
  167. check_errno
  168. sys_strerror
  169. sys_socket
  170. socket_to_fd
  171. sys_bind
  172. sys_connect
  173. sys_htons
  174. sys_ntohs
  175. sys_htonl
  176. sys_ntohl
  177. sys_inet_addr
  178. sys_gethostname
  179. sys_gethostbyname
  180. sys_getservbyname
  181. sys_getpeername
  182. sys_getaddrinfo
  183. sys_freeaddrinfo
  184. sys_shutdown
  185. sys_setsockopt
  186. sys_listen
  187. sys_getsockname
  188. sys_accept
  189. sys_recvfrom
  190. sys_sendto
  191. fcntl
  192. sys_close
  193. sys_dup
  194. sys_dup2
  195. pipe2
  196. _sys_read_ahead
  197. _sys_wait_accept
  198. _sys_wait_connect
  199. sys_read
  200. sys_write
  201. network_interface_get_info
  202. address_prefix_match
  203. network_interface_list
  204. network_interface_info
  205. w32_read_registry
  206. sys_localtime
  207. sys_clock
  208. w32_delayed_load
  209. check_windows_init_file
  210. term_ntproc
  211. init_ntproc
  212. shutdown_handler
  213. maybe_load_unicows_dll
  214. w32_relocate
  215. w32_my_exename
  216. realpath
  217. get_console_font_size
  218. w32_reexec_emacs
  219. globals_of_w32
  220. serial_open
  221. serial_configure
  222. register_aux_fd
  223. emacs_gnutls_pull
  224. emacs_gnutls_push

     1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
     2 
     3 Copyright (C) 1994-1995, 2000-2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 /*
    21    Geoff Voelker (voelker@cs.washington.edu)                         7-29-94
    22 */
    23 
    24 #define DEFER_MS_W32_H
    25 #include <config.h>
    26 
    27 #include <mingw_time.h>
    28 #include <stddef.h> /* for offsetof */
    29 #include <stdlib.h>
    30 #include <stdio.h>
    31 #include <float.h>      /* for DBL_EPSILON */
    32 #include <io.h>
    33 #include <errno.h>
    34 #include <fcntl.h>
    35 #include <ctype.h>
    36 #include <signal.h>
    37 #include <sys/file.h>
    38 #include <time.h>       /* must be before nt/inc/sys/time.h, for MinGW64 */
    39 #include <sys/time.h>
    40 #include <sys/utime.h>
    41 #include <math.h>
    42 #include <nproc.h>
    43 
    44 /* Include (most) CRT headers *before* ms-w32.h.  */
    45 #include <ms-w32.h>
    46 
    47 #include <string.h>     /* for strerror, needed by sys_strerror */
    48 #include <mbstring.h>   /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
    49 
    50 #undef access
    51 #undef chdir
    52 #undef chmod
    53 #undef creat
    54 #undef ctime
    55 #undef fopen
    56 #undef link
    57 #undef mkdir
    58 #undef open
    59 #undef rename
    60 #undef rmdir
    61 #undef unlink
    62 
    63 #undef close
    64 #undef dup
    65 #undef dup2
    66 #undef pipe
    67 #undef read
    68 #undef write
    69 
    70 #undef strerror
    71 
    72 #undef localtime
    73 
    74 #undef clock
    75 
    76 char *sys_ctime (const time_t *);
    77 int sys_chdir (const char *);
    78 int sys_creat (const char *, int);
    79 FILE *sys_fopen (const char *, const char *);
    80 int sys_open (const char *, int, int);
    81 int sys_rename (char const *, char const *);
    82 int sys_rmdir (const char *);
    83 int sys_close (int);
    84 int sys_dup2 (int, int);
    85 int sys_read (int, char *, unsigned int);
    86 int sys_write (int, const void *, unsigned int);
    87 struct tm *sys_localtime (const time_t *);
    88 /* MinGW64 system headers include string.h too early, causing the
    89    compiler to emit a warning about sys_strerror having no
    90    prototype.  */
    91 char *sys_strerror (int);
    92 clock_t sys_clock (void);
    93 
    94 #ifdef HAVE_MODULES
    95 extern void dynlib_reset_last_error (void);
    96 #endif
    97 
    98 #include "lisp.h"
    99 #include "epaths.h"     /* for PATH_EXEC */
   100 
   101 #include <pwd.h>
   102 #include <grp.h>
   103 
   104 #include <windows.h>
   105 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
   106    use a different name to avoid compilation problems.  */
   107 typedef struct _MEMORY_STATUS_EX {
   108   DWORD dwLength;
   109   DWORD dwMemoryLoad;
   110   DWORDLONG ullTotalPhys;
   111   DWORDLONG ullAvailPhys;
   112   DWORDLONG ullTotalPageFile;
   113   DWORDLONG ullAvailPageFile;
   114   DWORDLONG ullTotalVirtual;
   115   DWORDLONG ullAvailVirtual;
   116   DWORDLONG ullAvailExtendedVirtual;
   117 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
   118 
   119 /* These are here so that GDB would know about these data types.  This
   120    allows attaching GDB to Emacs when a fatal exception is triggered
   121    and Windows pops up the "application needs to be closed" dialog.
   122    At that point, _gnu_exception_handler, the top-level exception
   123    handler installed by the MinGW startup code, is somewhere on the
   124    call-stack of the main thread, so going to that call frame and
   125    looking at the argument to _gnu_exception_handler, which is a
   126    PEXCEPTION_POINTERS pointer, can reveal the exception code
   127    (excptr->ExceptionRecord->ExceptionCode) and the address where the
   128    exception happened (excptr->ExceptionRecord->ExceptionAddress), as
   129    well as some additional information specific to the exception.  */
   130 PEXCEPTION_POINTERS excptr;
   131 PEXCEPTION_RECORD excprec;
   132 PCONTEXT ctxrec;
   133 
   134 #include <lmcons.h>
   135 #include <shlobj.h>
   136 
   137 #include <tlhelp32.h>
   138 #include <psapi.h>
   139 #ifndef _MSC_VER
   140 #include <w32api.h>
   141 #endif
   142 #if _WIN32_WINNT < 0x0500
   143 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
   144 /* This either is not in psapi.h or guarded by higher value of
   145    _WIN32_WINNT than what we use.  w32api supplied with MinGW 3.15
   146    defines it in psapi.h  */
   147 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
   148   DWORD  cb;
   149   DWORD  PageFaultCount;
   150   SIZE_T PeakWorkingSetSize;
   151   SIZE_T WorkingSetSize;
   152   SIZE_T QuotaPeakPagedPoolUsage;
   153   SIZE_T QuotaPagedPoolUsage;
   154   SIZE_T QuotaPeakNonPagedPoolUsage;
   155   SIZE_T QuotaNonPagedPoolUsage;
   156   SIZE_T PagefileUsage;
   157   SIZE_T PeakPagefileUsage;
   158   SIZE_T PrivateUsage;
   159 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
   160 #endif
   161 #endif
   162 
   163 #include <winioctl.h>
   164 #include <aclapi.h>
   165 #include <sddl.h>
   166 
   167 #include <sys/acl.h>
   168 #include <acl.h>
   169 
   170 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
   171    define them by hand if not already defined.  */
   172 #ifndef SDDL_REVISION_1
   173 #define SDDL_REVISION_1 1
   174 #endif  /* SDDL_REVISION_1 */
   175 
   176 #if defined(_MSC_VER) || defined(MINGW_W64)
   177 /* MSVC and MinGW64 don't provide the definition of
   178    REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
   179    which cannot be included because it triggers conflicts with other
   180    Windows API headers.  So we define it here by hand.  */
   181 
   182 typedef struct _REPARSE_DATA_BUFFER {
   183     ULONG  ReparseTag;
   184     USHORT ReparseDataLength;
   185     USHORT Reserved;
   186     union {
   187         struct {
   188             USHORT SubstituteNameOffset;
   189             USHORT SubstituteNameLength;
   190             USHORT PrintNameOffset;
   191             USHORT PrintNameLength;
   192             ULONG Flags;
   193             WCHAR PathBuffer[1];
   194         } SymbolicLinkReparseBuffer;
   195         struct {
   196             USHORT SubstituteNameOffset;
   197             USHORT SubstituteNameLength;
   198             USHORT PrintNameOffset;
   199             USHORT PrintNameLength;
   200             WCHAR PathBuffer[1];
   201         } MountPointReparseBuffer;
   202         struct {
   203             UCHAR  DataBuffer[1];
   204         } GenericReparseBuffer;
   205     } DUMMYUNIONNAME;
   206 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
   207 
   208 #ifndef FILE_DEVICE_FILE_SYSTEM
   209 #define FILE_DEVICE_FILE_SYSTEM 9
   210 #endif
   211 #ifndef METHOD_BUFFERED
   212 #define METHOD_BUFFERED         0
   213 #endif
   214 #ifndef FILE_ANY_ACCESS
   215 #define FILE_ANY_ACCESS         0x00000000
   216 #endif
   217 #ifndef CTL_CODE
   218 #define CTL_CODE(t,f,m,a)       (((t)<<16)|((a)<<14)|((f)<<2)|(m))
   219 #endif
   220 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h.  */
   221 #ifndef FSCTL_GET_REPARSE_POINT
   222 #define FSCTL_GET_REPARSE_POINT \
   223   CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
   224 #endif
   225 #endif
   226 
   227 /* TCP connection support.  */
   228 #include <sys/socket.h>
   229 #undef socket
   230 #undef bind
   231 #undef connect
   232 #undef htons
   233 #undef ntohs
   234 #undef htonl
   235 #undef ntohl
   236 #undef inet_addr
   237 #undef gethostname
   238 #undef gethostbyname
   239 #undef getservbyname
   240 #undef getpeername
   241 #undef shutdown
   242 #undef setsockopt
   243 #undef listen
   244 #undef getsockname
   245 #undef accept
   246 #undef recvfrom
   247 #undef sendto
   248 
   249 /* We need at least XP level for GetAdaptersAddresses stuff.  */
   250 #if _WIN32_WINNT < 0x0501
   251 # undef ORIG_WIN32_WINNT
   252 # define ORIG_WIN32_WINNT _WIN32_WINNT
   253 # undef _WIN32_WINNT
   254 # define _WIN32_WINNT 0x0501
   255 #endif
   256 
   257 #include <iphlpapi.h>   /* should be after winsock2.h */
   258 
   259 #ifdef ORIG_WIN32_WINNT
   260 # undef _WIN32_WINNT
   261 # define _WIN32_WINNT ORIG_WIN32_WINNT
   262 # undef ORIG_WIN32_WINNT
   263 #endif
   264 
   265 #include <wincrypt.h>
   266 
   267 #include <c-strcase.h>
   268 #include <utimens.h>    /* for fdutimens */
   269 
   270 #include "w32.h"
   271 #include <dirent.h>
   272 #include "w32common.h"
   273 #include "w32select.h"
   274 #include "systime.h"            /* for current_timespec, struct timespec */
   275 #include "dispextern.h"         /* for xstrcasecmp */
   276 #include "coding.h"             /* for Vlocale_coding_system */
   277 
   278 #include "careadlinkat.h"
   279 #include "allocator.h"
   280 
   281 /* For Lisp_Process, serial_configure and serial_open.  */
   282 #include "process.h"
   283 #include "systty.h"
   284 
   285 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   286   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
   287 
   288 static DWORD get_rid (PSID);
   289 static int is_symlink (const char *);
   290 static char * chase_symlinks (const char *);
   291 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
   292 static int restore_privilege (TOKEN_PRIVILEGES *);
   293 static BOOL WINAPI revert_to_self (void);
   294 
   295 static int sys_access (const char *, int);
   296 extern void *e_malloc (size_t);
   297 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
   298                        const struct timespec *, const sigset_t *);
   299 extern int sys_dup (int);
   300 
   301 
   302 /* Initialization states.
   303 
   304    WARNING: If you add any more such variables for additional APIs,
   305             you MUST add initialization for them to globals_of_w32
   306             below.  This is because these variables might get set
   307             to non-NULL values during dumping, but the dumped Emacs
   308             cannot reuse those values, because it could be run on a
   309             different version of the OS, where API addresses are
   310             different.  */
   311 static BOOL g_b_init_is_windows_9x;
   312 static BOOL g_b_init_open_process_token;
   313 static BOOL g_b_init_get_token_information;
   314 static BOOL g_b_init_lookup_account_sid;
   315 static BOOL g_b_init_get_sid_sub_authority;
   316 static BOOL g_b_init_get_sid_sub_authority_count;
   317 static BOOL g_b_init_get_security_info;
   318 static BOOL g_b_init_get_file_security_w;
   319 static BOOL g_b_init_get_file_security_a;
   320 static BOOL g_b_init_get_security_descriptor_owner;
   321 static BOOL g_b_init_get_security_descriptor_group;
   322 static BOOL g_b_init_is_valid_sid;
   323 static BOOL g_b_init_create_toolhelp32_snapshot;
   324 static BOOL g_b_init_process32_first;
   325 static BOOL g_b_init_process32_next;
   326 static BOOL g_b_init_open_thread_token;
   327 static BOOL g_b_init_impersonate_self;
   328 static BOOL g_b_init_revert_to_self;
   329 static BOOL g_b_init_get_process_memory_info;
   330 static BOOL g_b_init_get_process_working_set_size;
   331 static BOOL g_b_init_global_memory_status;
   332 static BOOL g_b_init_global_memory_status_ex;
   333 static BOOL g_b_init_get_length_sid;
   334 static BOOL g_b_init_equal_sid;
   335 static BOOL g_b_init_copy_sid;
   336 static BOOL g_b_init_get_native_system_info;
   337 static BOOL g_b_init_get_system_times;
   338 static BOOL g_b_init_create_symbolic_link_w;
   339 static BOOL g_b_init_create_symbolic_link_a;
   340 static BOOL g_b_init_get_security_descriptor_dacl;
   341 static BOOL g_b_init_convert_sd_to_sddl;
   342 static BOOL g_b_init_convert_sddl_to_sd;
   343 static BOOL g_b_init_is_valid_security_descriptor;
   344 static BOOL g_b_init_set_file_security_w;
   345 static BOOL g_b_init_set_file_security_a;
   346 static BOOL g_b_init_set_named_security_info_w;
   347 static BOOL g_b_init_set_named_security_info_a;
   348 static BOOL g_b_init_get_adapters_info;
   349 static BOOL g_b_init_get_adapters_addresses;
   350 static BOOL g_b_init_reg_open_key_ex_w;
   351 static BOOL g_b_init_reg_query_value_ex_w;
   352 static BOOL g_b_init_expand_environment_strings_w;
   353 static BOOL g_b_init_get_user_default_ui_language;
   354 static BOOL g_b_init_get_console_font_size;
   355 
   356 BOOL g_b_init_compare_string_w;
   357 BOOL g_b_init_debug_break_process;
   358 
   359 /*
   360   BEGIN: Wrapper functions around OpenProcessToken
   361   and other functions in advapi32.dll that are only
   362   supported in Windows NT / 2k / XP
   363 */
   364   /* ** Function pointer typedefs ** */
   365 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
   366     HANDLE ProcessHandle,
   367     DWORD DesiredAccess,
   368     PHANDLE TokenHandle);
   369 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
   370     HANDLE TokenHandle,
   371     TOKEN_INFORMATION_CLASS TokenInformationClass,
   372     LPVOID TokenInformation,
   373     DWORD TokenInformationLength,
   374     PDWORD ReturnLength);
   375 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
   376     HANDLE process_handle,
   377     LPFILETIME creation_time,
   378     LPFILETIME exit_time,
   379     LPFILETIME kernel_time,
   380     LPFILETIME user_time);
   381 
   382 GetProcessTimes_Proc get_process_times_fn = NULL;
   383 
   384 #ifdef _UNICODE
   385 const char * const LookupAccountSid_Name = "LookupAccountSidW";
   386 #else
   387 const char * const LookupAccountSid_Name = "LookupAccountSidA";
   388 #endif
   389 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
   390     LPCTSTR lpSystemName,
   391     PSID Sid,
   392     LPTSTR Name,
   393     LPDWORD cbName,
   394     LPTSTR DomainName,
   395     LPDWORD cbDomainName,
   396     PSID_NAME_USE peUse);
   397 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
   398     PSID pSid,
   399     DWORD n);
   400 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
   401     PSID pSid);
   402 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
   403     HANDLE handle,
   404     SE_OBJECT_TYPE ObjectType,
   405     SECURITY_INFORMATION SecurityInfo,
   406     PSID *ppsidOwner,
   407     PSID *ppsidGroup,
   408     PACL *ppDacl,
   409     PACL *ppSacl,
   410     PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
   411 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
   412     LPCWSTR lpFileName,
   413     SECURITY_INFORMATION RequestedInformation,
   414     PSECURITY_DESCRIPTOR pSecurityDescriptor,
   415     DWORD nLength,
   416     LPDWORD lpnLengthNeeded);
   417 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
   418     LPCSTR lpFileName,
   419     SECURITY_INFORMATION RequestedInformation,
   420     PSECURITY_DESCRIPTOR pSecurityDescriptor,
   421     DWORD nLength,
   422     LPDWORD lpnLengthNeeded);
   423 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
   424     LPCWSTR lpFileName,
   425     SECURITY_INFORMATION SecurityInformation,
   426     PSECURITY_DESCRIPTOR pSecurityDescriptor);
   427 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
   428     LPCSTR lpFileName,
   429     SECURITY_INFORMATION SecurityInformation,
   430     PSECURITY_DESCRIPTOR pSecurityDescriptor);
   431 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
   432     LPCWSTR lpObjectName,
   433     SE_OBJECT_TYPE ObjectType,
   434     SECURITY_INFORMATION SecurityInformation,
   435     PSID psidOwner,
   436     PSID psidGroup,
   437     PACL pDacl,
   438     PACL pSacl);
   439 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
   440     LPCSTR lpObjectName,
   441     SE_OBJECT_TYPE ObjectType,
   442     SECURITY_INFORMATION SecurityInformation,
   443     PSID psidOwner,
   444     PSID psidGroup,
   445     PACL pDacl,
   446     PACL pSacl);
   447 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
   448     PSECURITY_DESCRIPTOR pSecurityDescriptor,
   449     PSID *pOwner,
   450     LPBOOL lpbOwnerDefaulted);
   451 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
   452     PSECURITY_DESCRIPTOR pSecurityDescriptor,
   453     PSID *pGroup,
   454     LPBOOL lpbGroupDefaulted);
   455 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
   456     PSECURITY_DESCRIPTOR pSecurityDescriptor,
   457     LPBOOL lpbDaclPresent,
   458     PACL *pDacl,
   459     LPBOOL lpbDaclDefaulted);
   460 typedef BOOL (WINAPI * IsValidSid_Proc) (
   461     PSID sid);
   462 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
   463     DWORD dwFlags,
   464     DWORD th32ProcessID);
   465 typedef BOOL (WINAPI * Process32First_Proc) (
   466     HANDLE hSnapshot,
   467     LPPROCESSENTRY32 lppe);
   468 typedef BOOL (WINAPI * Process32Next_Proc) (
   469     HANDLE hSnapshot,
   470     LPPROCESSENTRY32 lppe);
   471 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
   472     HANDLE ThreadHandle,
   473     DWORD DesiredAccess,
   474     BOOL OpenAsSelf,
   475     PHANDLE TokenHandle);
   476 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
   477     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
   478 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
   479 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
   480     HANDLE Process,
   481     PPROCESS_MEMORY_COUNTERS ppsmemCounters,
   482     DWORD cb);
   483 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
   484     HANDLE hProcess,
   485     PSIZE_T lpMinimumWorkingSetSize,
   486     PSIZE_T lpMaximumWorkingSetSize);
   487 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
   488     LPMEMORYSTATUS lpBuffer);
   489 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
   490     LPMEMORY_STATUS_EX lpBuffer);
   491 typedef BOOL (WINAPI * CopySid_Proc) (
   492     DWORD nDestinationSidLength,
   493     PSID pDestinationSid,
   494     PSID pSourceSid);
   495 typedef BOOL (WINAPI * EqualSid_Proc) (
   496     PSID pSid1,
   497     PSID pSid2);
   498 typedef DWORD (WINAPI * GetLengthSid_Proc) (
   499     PSID pSid);
   500 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
   501     LPSYSTEM_INFO lpSystemInfo);
   502 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
   503     LPFILETIME lpIdleTime,
   504     LPFILETIME lpKernelTime,
   505     LPFILETIME lpUserTime);
   506 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
   507     LPCWSTR lpSymlinkFileName,
   508     LPCWSTR lpTargetFileName,
   509     DWORD  dwFlags);
   510 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
   511     LPCSTR lpSymlinkFileName,
   512     LPCSTR lpTargetFileName,
   513     DWORD  dwFlags);
   514 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
   515     LPCTSTR StringSecurityDescriptor,
   516     DWORD StringSDRevision,
   517     PSECURITY_DESCRIPTOR  *SecurityDescriptor,
   518     PULONG  SecurityDescriptorSize);
   519 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
   520     PSECURITY_DESCRIPTOR  SecurityDescriptor,
   521     DWORD RequestedStringSDRevision,
   522     SECURITY_INFORMATION SecurityInformation,
   523     LPTSTR  *StringSecurityDescriptor,
   524     PULONG StringSecurityDescriptorLen);
   525 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
   526 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
   527     PIP_ADAPTER_INFO pAdapterInfo,
   528     PULONG pOutBufLen);
   529 typedef DWORD (WINAPI *GetAdaptersAddresses_Proc) (
   530     ULONG,
   531     ULONG,
   532     PVOID,
   533     PIP_ADAPTER_ADDRESSES,
   534     PULONG);
   535 
   536 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
   537 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
   538 DWORD multiByteToWideCharFlags;
   539 typedef LONG (WINAPI *RegOpenKeyExW_Proc) (HKEY,LPCWSTR,DWORD,REGSAM,PHKEY);
   540 typedef LONG (WINAPI *RegQueryValueExW_Proc) (HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD);
   541 typedef DWORD (WINAPI *ExpandEnvironmentStringsW_Proc) (LPCWSTR,LPWSTR,DWORD);
   542 typedef LANGID (WINAPI *GetUserDefaultUILanguage_Proc) (void);
   543 
   544 typedef COORD (WINAPI *GetConsoleFontSize_Proc) (HANDLE, DWORD);
   545 
   546 /* Old versions of mingw.org's MinGW, before v5.2.0, don't have a
   547    _WIN32_WINNT guard for CONSOLE_FONT_INFO in wincon.h, and so don't
   548    need the conditional definition below, which causes compilation
   549    errors.  Note: MinGW64 sets _WIN32_WINNT to a higher version, and
   550    its w32api.h version stays fixed at 3.14.  */
   551 #if _WIN32_WINNT < 0x0501 \
   552     && (__W32API_MAJOR_VERSION > 5 \
   553         || (__W32API_MAJOR_VERSION == 5 && __W32API_MINOR_VERSION >= 2))
   554 typedef struct
   555 {
   556   DWORD nFont;
   557   COORD dwFontSize;
   558 } CONSOLE_FONT_INFO;
   559 #endif
   560 
   561 typedef BOOL (WINAPI *GetCurrentConsoleFont_Proc) (
   562     HANDLE,
   563     BOOL,
   564     CONSOLE_FONT_INFO *);
   565 
   566 
   567   /* ** A utility function ** */
   568 static BOOL
   569 is_windows_9x (void)
   570 {
   571   static BOOL s_b_ret = 0;
   572   OSVERSIONINFO os_ver;
   573   if (g_b_init_is_windows_9x == 0)
   574     {
   575       g_b_init_is_windows_9x = 1;
   576       ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
   577       os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
   578       if (GetVersionEx (&os_ver))
   579         {
   580           s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
   581         }
   582     }
   583   return s_b_ret;
   584 }
   585 
   586 static Lisp_Object ltime (ULONGLONG);
   587 
   588 /* Get total user and system times for get-internal-run-time.
   589    Returns a list of integers if the times are provided by the OS
   590    (NT derivatives), otherwise it returns the result of current-time. */
   591 Lisp_Object
   592 w32_get_internal_run_time (void)
   593 {
   594   if (get_process_times_fn)
   595     {
   596       FILETIME create, exit, kernel, user;
   597       HANDLE proc = GetCurrentProcess ();
   598       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
   599         {
   600           LARGE_INTEGER user_int, kernel_int, total;
   601           user_int.LowPart = user.dwLowDateTime;
   602           user_int.HighPart = user.dwHighDateTime;
   603           kernel_int.LowPart = kernel.dwLowDateTime;
   604           kernel_int.HighPart = kernel.dwHighDateTime;
   605           total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
   606           return ltime (total.QuadPart);
   607         }
   608     }
   609 
   610   return Fcurrent_time ();
   611 }
   612 
   613   /* ** The wrapper functions ** */
   614 
   615 static BOOL WINAPI
   616 open_process_token (HANDLE ProcessHandle,
   617                     DWORD DesiredAccess,
   618                     PHANDLE TokenHandle)
   619 {
   620   static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
   621   HMODULE hm_advapi32 = NULL;
   622   if (is_windows_9x () == TRUE)
   623     {
   624       return FALSE;
   625     }
   626   if (g_b_init_open_process_token == 0)
   627     {
   628       g_b_init_open_process_token = 1;
   629       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   630       s_pfn_Open_Process_Token = (OpenProcessToken_Proc)
   631         get_proc_addr (hm_advapi32, "OpenProcessToken");
   632     }
   633   if (s_pfn_Open_Process_Token == NULL)
   634     {
   635       return FALSE;
   636     }
   637   return (
   638       s_pfn_Open_Process_Token (
   639           ProcessHandle,
   640           DesiredAccess,
   641           TokenHandle)
   642       );
   643 }
   644 
   645 static BOOL WINAPI
   646 get_token_information (HANDLE TokenHandle,
   647                        TOKEN_INFORMATION_CLASS TokenInformationClass,
   648                        LPVOID TokenInformation,
   649                        DWORD TokenInformationLength,
   650                        PDWORD ReturnLength)
   651 {
   652   static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
   653   HMODULE hm_advapi32 = NULL;
   654   if (is_windows_9x () == TRUE)
   655     {
   656       return FALSE;
   657     }
   658   if (g_b_init_get_token_information == 0)
   659     {
   660       g_b_init_get_token_information = 1;
   661       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   662       s_pfn_Get_Token_Information = (GetTokenInformation_Proc)
   663         get_proc_addr (hm_advapi32, "GetTokenInformation");
   664     }
   665   if (s_pfn_Get_Token_Information == NULL)
   666     {
   667       return FALSE;
   668     }
   669   return (
   670       s_pfn_Get_Token_Information (
   671           TokenHandle,
   672           TokenInformationClass,
   673           TokenInformation,
   674           TokenInformationLength,
   675           ReturnLength)
   676       );
   677 }
   678 
   679 static BOOL WINAPI
   680 lookup_account_sid (LPCTSTR lpSystemName,
   681                     PSID Sid,
   682                     LPTSTR Name,
   683                     LPDWORD cbName,
   684                     LPTSTR DomainName,
   685                     LPDWORD cbDomainName,
   686                     PSID_NAME_USE peUse)
   687 {
   688   static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
   689   HMODULE hm_advapi32 = NULL;
   690   if (is_windows_9x () == TRUE)
   691     {
   692       return FALSE;
   693     }
   694   if (g_b_init_lookup_account_sid == 0)
   695     {
   696       g_b_init_lookup_account_sid = 1;
   697       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   698       s_pfn_Lookup_Account_Sid = (LookupAccountSid_Proc)
   699         get_proc_addr (hm_advapi32, LookupAccountSid_Name);
   700     }
   701   if (s_pfn_Lookup_Account_Sid == NULL)
   702     {
   703       return FALSE;
   704     }
   705   return (
   706       s_pfn_Lookup_Account_Sid (
   707           lpSystemName,
   708           Sid,
   709           Name,
   710           cbName,
   711           DomainName,
   712           cbDomainName,
   713           peUse)
   714       );
   715 }
   716 
   717 static PDWORD WINAPI
   718 get_sid_sub_authority (PSID pSid, DWORD n)
   719 {
   720   static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
   721   static DWORD zero = 0U;
   722   HMODULE hm_advapi32 = NULL;
   723   if (is_windows_9x () == TRUE)
   724     {
   725       return &zero;
   726     }
   727   if (g_b_init_get_sid_sub_authority == 0)
   728     {
   729       g_b_init_get_sid_sub_authority = 1;
   730       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   731       s_pfn_Get_Sid_Sub_Authority = (GetSidSubAuthority_Proc)
   732         get_proc_addr (hm_advapi32, "GetSidSubAuthority");
   733     }
   734   if (s_pfn_Get_Sid_Sub_Authority == NULL)
   735     {
   736       return &zero;
   737     }
   738   return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
   739 }
   740 
   741 static PUCHAR WINAPI
   742 get_sid_sub_authority_count (PSID pSid)
   743 {
   744   static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
   745   static UCHAR zero = 0U;
   746   HMODULE hm_advapi32 = NULL;
   747   if (is_windows_9x () == TRUE)
   748     {
   749       return &zero;
   750     }
   751   if (g_b_init_get_sid_sub_authority_count == 0)
   752     {
   753       g_b_init_get_sid_sub_authority_count = 1;
   754       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   755       s_pfn_Get_Sid_Sub_Authority_Count = (GetSidSubAuthorityCount_Proc)
   756         get_proc_addr (hm_advapi32, "GetSidSubAuthorityCount");
   757     }
   758   if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
   759     {
   760       return &zero;
   761     }
   762   return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
   763 }
   764 
   765 static DWORD WINAPI
   766 get_security_info (HANDLE handle,
   767                    SE_OBJECT_TYPE ObjectType,
   768                    SECURITY_INFORMATION SecurityInfo,
   769                    PSID *ppsidOwner,
   770                    PSID *ppsidGroup,
   771                    PACL *ppDacl,
   772                    PACL *ppSacl,
   773                    PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
   774 {
   775   static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
   776   HMODULE hm_advapi32 = NULL;
   777   if (is_windows_9x () == TRUE)
   778     {
   779       return FALSE;
   780     }
   781   if (g_b_init_get_security_info == 0)
   782     {
   783       g_b_init_get_security_info = 1;
   784       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   785       s_pfn_Get_Security_Info = (GetSecurityInfo_Proc)
   786         get_proc_addr (hm_advapi32, "GetSecurityInfo");
   787     }
   788   if (s_pfn_Get_Security_Info == NULL)
   789     {
   790       return FALSE;
   791     }
   792   return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
   793                                    ppsidOwner, ppsidGroup, ppDacl, ppSacl,
   794                                    ppSecurityDescriptor));
   795 }
   796 
   797 static BOOL WINAPI
   798 get_file_security (const char *lpFileName,
   799                    SECURITY_INFORMATION RequestedInformation,
   800                    PSECURITY_DESCRIPTOR pSecurityDescriptor,
   801                    DWORD nLength,
   802                    LPDWORD lpnLengthNeeded)
   803 {
   804   static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
   805   static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
   806   HMODULE hm_advapi32 = NULL;
   807   if (is_windows_9x () == TRUE)
   808     {
   809       errno = ENOTSUP;
   810       return FALSE;
   811     }
   812   if (w32_unicode_filenames)
   813     {
   814       wchar_t filename_w[MAX_PATH];
   815 
   816       if (g_b_init_get_file_security_w == 0)
   817         {
   818           g_b_init_get_file_security_w = 1;
   819           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   820           s_pfn_Get_File_SecurityW = (GetFileSecurityW_Proc)
   821             get_proc_addr (hm_advapi32, "GetFileSecurityW");
   822         }
   823       if (s_pfn_Get_File_SecurityW == NULL)
   824         {
   825           errno = ENOTSUP;
   826           return FALSE;
   827         }
   828       filename_to_utf16 (lpFileName, filename_w);
   829       return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
   830                                         pSecurityDescriptor, nLength,
   831                                         lpnLengthNeeded));
   832     }
   833   else
   834     {
   835       char filename_a[MAX_PATH];
   836 
   837       if (g_b_init_get_file_security_a == 0)
   838         {
   839           g_b_init_get_file_security_a = 1;
   840           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   841           s_pfn_Get_File_SecurityA = (GetFileSecurityA_Proc)
   842             get_proc_addr (hm_advapi32, "GetFileSecurityA");
   843         }
   844       if (s_pfn_Get_File_SecurityA == NULL)
   845         {
   846           errno = ENOTSUP;
   847           return FALSE;
   848         }
   849       filename_to_ansi (lpFileName, filename_a);
   850       return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
   851                                         pSecurityDescriptor, nLength,
   852                                         lpnLengthNeeded));
   853     }
   854 }
   855 
   856 static BOOL WINAPI
   857 set_file_security (const char *lpFileName,
   858                    SECURITY_INFORMATION SecurityInformation,
   859                    PSECURITY_DESCRIPTOR pSecurityDescriptor)
   860 {
   861   static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
   862   static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
   863   HMODULE hm_advapi32 = NULL;
   864   if (is_windows_9x () == TRUE)
   865     {
   866       errno = ENOTSUP;
   867       return FALSE;
   868     }
   869   if (w32_unicode_filenames)
   870     {
   871       wchar_t filename_w[MAX_PATH];
   872 
   873       if (g_b_init_set_file_security_w == 0)
   874         {
   875           g_b_init_set_file_security_w = 1;
   876           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   877           s_pfn_Set_File_SecurityW = (SetFileSecurityW_Proc)
   878             get_proc_addr (hm_advapi32, "SetFileSecurityW");
   879         }
   880       if (s_pfn_Set_File_SecurityW == NULL)
   881         {
   882           errno = ENOTSUP;
   883           return FALSE;
   884         }
   885       filename_to_utf16 (lpFileName, filename_w);
   886       return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
   887                                         pSecurityDescriptor));
   888     }
   889   else
   890     {
   891       char filename_a[MAX_PATH];
   892 
   893       if (g_b_init_set_file_security_a == 0)
   894         {
   895           g_b_init_set_file_security_a = 1;
   896           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   897           s_pfn_Set_File_SecurityA = (SetFileSecurityA_Proc)
   898             get_proc_addr (hm_advapi32, "SetFileSecurityA");
   899         }
   900       if (s_pfn_Set_File_SecurityA == NULL)
   901         {
   902           errno = ENOTSUP;
   903           return FALSE;
   904         }
   905       filename_to_ansi (lpFileName, filename_a);
   906       return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
   907                                         pSecurityDescriptor));
   908     }
   909 }
   910 
   911 static DWORD WINAPI
   912 set_named_security_info (LPCTSTR lpObjectName,
   913                          SE_OBJECT_TYPE ObjectType,
   914                          SECURITY_INFORMATION SecurityInformation,
   915                          PSID psidOwner,
   916                          PSID psidGroup,
   917                          PACL pDacl,
   918                          PACL pSacl)
   919 {
   920   static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
   921   static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
   922   HMODULE hm_advapi32 = NULL;
   923   if (is_windows_9x () == TRUE)
   924     {
   925       errno = ENOTSUP;
   926       return ENOTSUP;
   927     }
   928   if (w32_unicode_filenames)
   929     {
   930       wchar_t filename_w[MAX_PATH];
   931 
   932       if (g_b_init_set_named_security_info_w == 0)
   933         {
   934           g_b_init_set_named_security_info_w = 1;
   935           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   936           s_pfn_Set_Named_Security_InfoW = (SetNamedSecurityInfoW_Proc)
   937             get_proc_addr (hm_advapi32, "SetNamedSecurityInfoW");
   938         }
   939       if (s_pfn_Set_Named_Security_InfoW == NULL)
   940         {
   941           errno = ENOTSUP;
   942           return ENOTSUP;
   943         }
   944       filename_to_utf16 (lpObjectName, filename_w);
   945       return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
   946                                               SecurityInformation, psidOwner,
   947                                               psidGroup, pDacl, pSacl));
   948     }
   949   else
   950     {
   951       char filename_a[MAX_PATH];
   952 
   953       if (g_b_init_set_named_security_info_a == 0)
   954         {
   955           g_b_init_set_named_security_info_a = 1;
   956           hm_advapi32 = LoadLibrary ("Advapi32.dll");
   957           s_pfn_Set_Named_Security_InfoA = (SetNamedSecurityInfoA_Proc)
   958             get_proc_addr (hm_advapi32, "SetNamedSecurityInfoA");
   959         }
   960       if (s_pfn_Set_Named_Security_InfoA == NULL)
   961         {
   962           errno = ENOTSUP;
   963           return ENOTSUP;
   964         }
   965       filename_to_ansi (lpObjectName, filename_a);
   966       return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
   967                                               SecurityInformation, psidOwner,
   968                                               psidGroup, pDacl, pSacl));
   969     }
   970 }
   971 
   972 static BOOL WINAPI
   973 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
   974                                PSID *pOwner,
   975                                LPBOOL lpbOwnerDefaulted)
   976 {
   977   static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
   978   HMODULE hm_advapi32 = NULL;
   979   if (is_windows_9x () == TRUE)
   980     {
   981       errno = ENOTSUP;
   982       return FALSE;
   983     }
   984   if (g_b_init_get_security_descriptor_owner == 0)
   985     {
   986       g_b_init_get_security_descriptor_owner = 1;
   987       hm_advapi32 = LoadLibrary ("Advapi32.dll");
   988       s_pfn_Get_Security_Descriptor_Owner = (GetSecurityDescriptorOwner_Proc)
   989         get_proc_addr (hm_advapi32, "GetSecurityDescriptorOwner");
   990     }
   991   if (s_pfn_Get_Security_Descriptor_Owner == NULL)
   992     {
   993       errno = ENOTSUP;
   994       return FALSE;
   995     }
   996   return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
   997                                                lpbOwnerDefaulted));
   998 }
   999 
  1000 static BOOL WINAPI
  1001 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1002                                PSID *pGroup,
  1003                                LPBOOL lpbGroupDefaulted)
  1004 {
  1005   static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
  1006   HMODULE hm_advapi32 = NULL;
  1007   if (is_windows_9x () == TRUE)
  1008     {
  1009       errno = ENOTSUP;
  1010       return FALSE;
  1011     }
  1012   if (g_b_init_get_security_descriptor_group == 0)
  1013     {
  1014       g_b_init_get_security_descriptor_group = 1;
  1015       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1016       s_pfn_Get_Security_Descriptor_Group = (GetSecurityDescriptorGroup_Proc)
  1017         get_proc_addr (hm_advapi32, "GetSecurityDescriptorGroup");
  1018     }
  1019   if (s_pfn_Get_Security_Descriptor_Group == NULL)
  1020     {
  1021       errno = ENOTSUP;
  1022       return FALSE;
  1023     }
  1024   return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
  1025                                                lpbGroupDefaulted));
  1026 }
  1027 
  1028 static BOOL WINAPI
  1029 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1030                               LPBOOL lpbDaclPresent,
  1031                               PACL *pDacl,
  1032                               LPBOOL lpbDaclDefaulted)
  1033 {
  1034   static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
  1035   HMODULE hm_advapi32 = NULL;
  1036   if (is_windows_9x () == TRUE)
  1037     {
  1038       errno = ENOTSUP;
  1039       return FALSE;
  1040     }
  1041   if (g_b_init_get_security_descriptor_dacl == 0)
  1042     {
  1043       g_b_init_get_security_descriptor_dacl = 1;
  1044       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1045       s_pfn_Get_Security_Descriptor_Dacl = (GetSecurityDescriptorDacl_Proc)
  1046         get_proc_addr (hm_advapi32, "GetSecurityDescriptorDacl");
  1047     }
  1048   if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
  1049     {
  1050       errno = ENOTSUP;
  1051       return FALSE;
  1052     }
  1053   return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
  1054                                               lpbDaclPresent, pDacl,
  1055                                               lpbDaclDefaulted));
  1056 }
  1057 
  1058 static BOOL WINAPI
  1059 is_valid_sid (PSID sid)
  1060 {
  1061   static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
  1062   HMODULE hm_advapi32 = NULL;
  1063   if (is_windows_9x () == TRUE)
  1064     {
  1065       return FALSE;
  1066     }
  1067   if (g_b_init_is_valid_sid == 0)
  1068     {
  1069       g_b_init_is_valid_sid = 1;
  1070       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1071       s_pfn_Is_Valid_Sid = (IsValidSid_Proc)
  1072         get_proc_addr (hm_advapi32, "IsValidSid");
  1073     }
  1074   if (s_pfn_Is_Valid_Sid == NULL)
  1075     {
  1076       return FALSE;
  1077     }
  1078   return (s_pfn_Is_Valid_Sid (sid));
  1079 }
  1080 
  1081 static BOOL WINAPI
  1082 equal_sid (PSID sid1, PSID sid2)
  1083 {
  1084   static EqualSid_Proc s_pfn_Equal_Sid = NULL;
  1085   HMODULE hm_advapi32 = NULL;
  1086   if (is_windows_9x () == TRUE)
  1087     {
  1088       return FALSE;
  1089     }
  1090   if (g_b_init_equal_sid == 0)
  1091     {
  1092       g_b_init_equal_sid = 1;
  1093       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1094       s_pfn_Equal_Sid = (EqualSid_Proc)
  1095         get_proc_addr (hm_advapi32, "EqualSid");
  1096     }
  1097   if (s_pfn_Equal_Sid == NULL)
  1098     {
  1099       return FALSE;
  1100     }
  1101   return (s_pfn_Equal_Sid (sid1, sid2));
  1102 }
  1103 
  1104 static DWORD WINAPI
  1105 get_length_sid (PSID sid)
  1106 {
  1107   static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
  1108   HMODULE hm_advapi32 = NULL;
  1109   if (is_windows_9x () == TRUE)
  1110     {
  1111       return 0;
  1112     }
  1113   if (g_b_init_get_length_sid == 0)
  1114     {
  1115       g_b_init_get_length_sid = 1;
  1116       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1117       s_pfn_Get_Length_Sid = (GetLengthSid_Proc)
  1118         get_proc_addr (hm_advapi32, "GetLengthSid");
  1119     }
  1120   if (s_pfn_Get_Length_Sid == NULL)
  1121     {
  1122       return 0;
  1123     }
  1124   return (s_pfn_Get_Length_Sid (sid));
  1125 }
  1126 
  1127 static BOOL WINAPI
  1128 copy_sid (DWORD destlen, PSID dest, PSID src)
  1129 {
  1130   static CopySid_Proc s_pfn_Copy_Sid = NULL;
  1131   HMODULE hm_advapi32 = NULL;
  1132   if (is_windows_9x () == TRUE)
  1133     {
  1134       return FALSE;
  1135     }
  1136   if (g_b_init_copy_sid == 0)
  1137     {
  1138       g_b_init_copy_sid = 1;
  1139       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1140       s_pfn_Copy_Sid = (CopySid_Proc)
  1141         get_proc_addr (hm_advapi32, "CopySid");
  1142     }
  1143   if (s_pfn_Copy_Sid == NULL)
  1144     {
  1145       return FALSE;
  1146     }
  1147   return (s_pfn_Copy_Sid (destlen, dest, src));
  1148 }
  1149 
  1150 /*
  1151   END: Wrapper functions around OpenProcessToken
  1152   and other functions in advapi32.dll that are only
  1153   supported in Windows NT / 2k / XP
  1154 */
  1155 
  1156 static void WINAPI
  1157 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
  1158 {
  1159   static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
  1160   if (is_windows_9x () != TRUE)
  1161     {
  1162       if (g_b_init_get_native_system_info == 0)
  1163         {
  1164           g_b_init_get_native_system_info = 1;
  1165           s_pfn_Get_Native_System_Info = (GetNativeSystemInfo_Proc)
  1166             get_proc_addr (GetModuleHandle ("kernel32.dll"),
  1167                                   "GetNativeSystemInfo");
  1168         }
  1169       if (s_pfn_Get_Native_System_Info != NULL)
  1170         s_pfn_Get_Native_System_Info (lpSystemInfo);
  1171     }
  1172   else
  1173     lpSystemInfo->dwNumberOfProcessors = -1;
  1174 }
  1175 
  1176 static BOOL WINAPI
  1177 get_system_times (LPFILETIME lpIdleTime,
  1178                   LPFILETIME lpKernelTime,
  1179                   LPFILETIME lpUserTime)
  1180 {
  1181   static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
  1182   if (is_windows_9x () == TRUE)
  1183     {
  1184       return FALSE;
  1185     }
  1186   if (g_b_init_get_system_times == 0)
  1187     {
  1188       g_b_init_get_system_times = 1;
  1189       s_pfn_Get_System_times = (GetSystemTimes_Proc)
  1190         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  1191                               "GetSystemTimes");
  1192     }
  1193   if (s_pfn_Get_System_times == NULL)
  1194     return FALSE;
  1195   return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
  1196 }
  1197 
  1198 static BOOLEAN WINAPI
  1199 create_symbolic_link (LPCSTR lpSymlinkFilename,
  1200                       LPCSTR lpTargetFileName,
  1201                       DWORD dwFlags)
  1202 {
  1203   static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
  1204   static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
  1205   BOOLEAN retval;
  1206 
  1207   if (is_windows_9x () == TRUE)
  1208     {
  1209       errno = ENOSYS;
  1210       return 0;
  1211     }
  1212   if (w32_unicode_filenames)
  1213     {
  1214       wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
  1215 
  1216       if (g_b_init_create_symbolic_link_w == 0)
  1217         {
  1218           g_b_init_create_symbolic_link_w = 1;
  1219           s_pfn_Create_Symbolic_LinkW = (CreateSymbolicLinkW_Proc)
  1220             get_proc_addr (GetModuleHandle ("kernel32.dll"),
  1221                                   "CreateSymbolicLinkW");
  1222         }
  1223       if (s_pfn_Create_Symbolic_LinkW == NULL)
  1224         {
  1225           errno = ENOSYS;
  1226           return 0;
  1227         }
  1228 
  1229       filename_to_utf16 (lpSymlinkFilename, symfn_w);
  1230       filename_to_utf16 (lpTargetFileName, tgtfn_w);
  1231       retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
  1232       /* If we were denied creation of the symlink, try again after
  1233          enabling the SeCreateSymbolicLinkPrivilege for our process.  */
  1234       if (!retval)
  1235         {
  1236           TOKEN_PRIVILEGES priv_current;
  1237 
  1238           if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
  1239                                 &priv_current))
  1240             {
  1241               retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
  1242               restore_privilege (&priv_current);
  1243               revert_to_self ();
  1244             }
  1245         }
  1246     }
  1247   else
  1248     {
  1249       char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
  1250 
  1251       if (g_b_init_create_symbolic_link_a == 0)
  1252         {
  1253           g_b_init_create_symbolic_link_a = 1;
  1254           s_pfn_Create_Symbolic_LinkA = (CreateSymbolicLinkA_Proc)
  1255             get_proc_addr (GetModuleHandle ("kernel32.dll"),
  1256                                   "CreateSymbolicLinkA");
  1257         }
  1258       if (s_pfn_Create_Symbolic_LinkA == NULL)
  1259         {
  1260           errno = ENOSYS;
  1261           return 0;
  1262         }
  1263 
  1264       filename_to_ansi (lpSymlinkFilename, symfn_a);
  1265       filename_to_ansi (lpTargetFileName, tgtfn_a);
  1266       retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
  1267       /* If we were denied creation of the symlink, try again after
  1268          enabling the SeCreateSymbolicLinkPrivilege for our process.  */
  1269       if (!retval)
  1270         {
  1271           TOKEN_PRIVILEGES priv_current;
  1272 
  1273           if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
  1274                                 &priv_current))
  1275             {
  1276               retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
  1277               restore_privilege (&priv_current);
  1278               revert_to_self ();
  1279             }
  1280         }
  1281     }
  1282   return retval;
  1283 }
  1284 
  1285 static BOOL WINAPI
  1286 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
  1287 {
  1288   static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
  1289 
  1290   if (is_windows_9x () == TRUE)
  1291     {
  1292       errno = ENOTSUP;
  1293       return FALSE;
  1294     }
  1295 
  1296   if (g_b_init_is_valid_security_descriptor == 0)
  1297     {
  1298       g_b_init_is_valid_security_descriptor = 1;
  1299       s_pfn_Is_Valid_Security_Descriptor_Proc = (IsValidSecurityDescriptor_Proc)
  1300         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
  1301                               "IsValidSecurityDescriptor");
  1302     }
  1303   if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
  1304     {
  1305       errno = ENOTSUP;
  1306       return FALSE;
  1307     }
  1308 
  1309   return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
  1310 }
  1311 
  1312 static BOOL WINAPI
  1313 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
  1314                     DWORD RequestedStringSDRevision,
  1315                     SECURITY_INFORMATION SecurityInformation,
  1316                     LPTSTR  *StringSecurityDescriptor,
  1317                     PULONG StringSecurityDescriptorLen)
  1318 {
  1319   static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
  1320   BOOL retval;
  1321 
  1322   if (is_windows_9x () == TRUE)
  1323     {
  1324       errno = ENOTSUP;
  1325       return FALSE;
  1326     }
  1327 
  1328   if (g_b_init_convert_sd_to_sddl == 0)
  1329     {
  1330       g_b_init_convert_sd_to_sddl = 1;
  1331 #ifdef _UNICODE
  1332       s_pfn_Convert_SD_To_SDDL =
  1333         (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
  1334         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
  1335                               "ConvertSecurityDescriptorToStringSecurityDescriptorW");
  1336 #else
  1337       s_pfn_Convert_SD_To_SDDL =
  1338         (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
  1339         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
  1340                               "ConvertSecurityDescriptorToStringSecurityDescriptorA");
  1341 #endif
  1342     }
  1343   if (s_pfn_Convert_SD_To_SDDL == NULL)
  1344     {
  1345       errno = ENOTSUP;
  1346       return FALSE;
  1347     }
  1348 
  1349   retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
  1350                                      RequestedStringSDRevision,
  1351                                      SecurityInformation,
  1352                                      StringSecurityDescriptor,
  1353                                      StringSecurityDescriptorLen);
  1354 
  1355   return retval;
  1356 }
  1357 
  1358 static BOOL WINAPI
  1359 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
  1360                     DWORD StringSDRevision,
  1361                     PSECURITY_DESCRIPTOR  *SecurityDescriptor,
  1362                     PULONG  SecurityDescriptorSize)
  1363 {
  1364   static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
  1365   BOOL retval;
  1366 
  1367   if (is_windows_9x () == TRUE)
  1368     {
  1369       errno = ENOTSUP;
  1370       return FALSE;
  1371     }
  1372 
  1373   if (g_b_init_convert_sddl_to_sd == 0)
  1374     {
  1375       g_b_init_convert_sddl_to_sd = 1;
  1376 #ifdef _UNICODE
  1377       s_pfn_Convert_SDDL_To_SD =
  1378         (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)
  1379         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
  1380                               "ConvertStringSecurityDescriptorToSecurityDescriptorW");
  1381 #else
  1382       s_pfn_Convert_SDDL_To_SD =
  1383         (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)
  1384         get_proc_addr (GetModuleHandle ("Advapi32.dll"),
  1385                               "ConvertStringSecurityDescriptorToSecurityDescriptorA");
  1386 #endif
  1387     }
  1388   if (s_pfn_Convert_SDDL_To_SD == NULL)
  1389     {
  1390       errno = ENOTSUP;
  1391       return FALSE;
  1392     }
  1393 
  1394   retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
  1395                                      StringSDRevision,
  1396                                      SecurityDescriptor,
  1397                                      SecurityDescriptorSize);
  1398 
  1399   return retval;
  1400 }
  1401 
  1402 static DWORD WINAPI
  1403 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
  1404 {
  1405   static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
  1406   HMODULE hm_iphlpapi = NULL;
  1407 
  1408   if (is_windows_9x () == TRUE)
  1409     return ERROR_NOT_SUPPORTED;
  1410 
  1411   if (g_b_init_get_adapters_info == 0)
  1412     {
  1413       g_b_init_get_adapters_info = 1;
  1414       hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
  1415       if (hm_iphlpapi)
  1416         s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
  1417           get_proc_addr (hm_iphlpapi, "GetAdaptersInfo");
  1418     }
  1419   if (s_pfn_Get_Adapters_Info == NULL)
  1420     return ERROR_NOT_SUPPORTED;
  1421   return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
  1422 }
  1423 
  1424 static DWORD WINAPI
  1425 get_adapters_addresses (ULONG family, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen)
  1426 {
  1427   static GetAdaptersAddresses_Proc s_pfn_Get_Adapters_Addresses = NULL;
  1428   HMODULE hm_iphlpapi = NULL;
  1429 
  1430   if (is_windows_9x () == TRUE)
  1431     return ERROR_NOT_SUPPORTED;
  1432 
  1433   if (g_b_init_get_adapters_addresses == 0)
  1434     {
  1435       g_b_init_get_adapters_addresses = 1;
  1436       hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
  1437       if (hm_iphlpapi)
  1438         s_pfn_Get_Adapters_Addresses = (GetAdaptersAddresses_Proc)
  1439           get_proc_addr (hm_iphlpapi, "GetAdaptersAddresses");
  1440     }
  1441   if (s_pfn_Get_Adapters_Addresses == NULL)
  1442     return ERROR_NOT_SUPPORTED;
  1443   ULONG flags = GAA_FLAG_SKIP_ANYCAST
  1444     | GAA_FLAG_SKIP_MULTICAST
  1445     | GAA_FLAG_SKIP_DNS_SERVER;
  1446   return s_pfn_Get_Adapters_Addresses (family, flags, NULL, pAdapterAddresses, pOutBufLen);
  1447 }
  1448 
  1449 static LONG WINAPI
  1450 reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions,
  1451                    REGSAM samDesired, PHKEY phkResult)
  1452 {
  1453   static RegOpenKeyExW_Proc s_pfn_Reg_Open_Key_Ex_w = NULL;
  1454   HMODULE hm_advapi32 = NULL;
  1455 
  1456   if (is_windows_9x () == TRUE)
  1457     return ERROR_NOT_SUPPORTED;
  1458 
  1459   if (g_b_init_reg_open_key_ex_w == 0)
  1460     {
  1461       g_b_init_reg_open_key_ex_w = 1;
  1462       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1463       if (hm_advapi32)
  1464         s_pfn_Reg_Open_Key_Ex_w = (RegOpenKeyExW_Proc)
  1465           get_proc_addr (hm_advapi32, "RegOpenKeyExW");
  1466     }
  1467   if (s_pfn_Reg_Open_Key_Ex_w == NULL)
  1468     return ERROR_NOT_SUPPORTED;
  1469   return s_pfn_Reg_Open_Key_Ex_w (hkey, lpSubKey, ulOptions,
  1470                                   samDesired, phkResult);
  1471 }
  1472 
  1473 static LONG WINAPI
  1474 reg_query_value_ex_w (HKEY hkey, LPCWSTR lpValueName, LPDWORD lpReserved,
  1475                       LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
  1476 {
  1477   static RegQueryValueExW_Proc s_pfn_Reg_Query_Value_Ex_w = NULL;
  1478   HMODULE hm_advapi32 = NULL;
  1479 
  1480   if (is_windows_9x () == TRUE)
  1481     return ERROR_NOT_SUPPORTED;
  1482 
  1483   if (g_b_init_reg_query_value_ex_w == 0)
  1484     {
  1485       g_b_init_reg_query_value_ex_w = 1;
  1486       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  1487       if (hm_advapi32)
  1488         s_pfn_Reg_Query_Value_Ex_w = (RegQueryValueExW_Proc)
  1489           get_proc_addr (hm_advapi32, "RegQueryValueExW");
  1490     }
  1491   if (s_pfn_Reg_Query_Value_Ex_w == NULL)
  1492     return ERROR_NOT_SUPPORTED;
  1493   return s_pfn_Reg_Query_Value_Ex_w (hkey, lpValueName, lpReserved,
  1494                                      lpType, lpData, lpcbData);
  1495 }
  1496 
  1497 static DWORD WINAPI
  1498 expand_environment_strings_w (LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
  1499 {
  1500   static ExpandEnvironmentStringsW_Proc s_pfn_Expand_Environment_Strings_w = NULL;
  1501   HMODULE hm_kernel32 = NULL;
  1502 
  1503   if (is_windows_9x () == TRUE)
  1504     return ERROR_NOT_SUPPORTED;
  1505 
  1506   if (g_b_init_expand_environment_strings_w == 0)
  1507     {
  1508       g_b_init_expand_environment_strings_w = 1;
  1509       hm_kernel32 = LoadLibrary ("Kernel32.dll");
  1510       if (hm_kernel32)
  1511         s_pfn_Expand_Environment_Strings_w = (ExpandEnvironmentStringsW_Proc)
  1512           get_proc_addr (hm_kernel32, "ExpandEnvironmentStringsW");
  1513     }
  1514   if (s_pfn_Expand_Environment_Strings_w == NULL)
  1515     {
  1516       errno = ENOSYS;
  1517       return FALSE;
  1518     }
  1519   return s_pfn_Expand_Environment_Strings_w (lpSrc, lpDst, nSize);
  1520 }
  1521 
  1522 static LANGID WINAPI
  1523 get_user_default_ui_language (void)
  1524 {
  1525   static GetUserDefaultUILanguage_Proc s_pfn_GetUserDefaultUILanguage = NULL;
  1526   HMODULE hm_kernel32 = NULL;
  1527 
  1528   if (is_windows_9x () == TRUE)
  1529     return 0;
  1530 
  1531   if (g_b_init_get_user_default_ui_language == 0)
  1532     {
  1533       g_b_init_get_user_default_ui_language = 1;
  1534       hm_kernel32 = LoadLibrary ("Kernel32.dll");
  1535       if (hm_kernel32)
  1536         s_pfn_GetUserDefaultUILanguage = (GetUserDefaultUILanguage_Proc)
  1537           get_proc_addr (hm_kernel32, "GetUserDefaultUILanguage");
  1538     }
  1539   if (s_pfn_GetUserDefaultUILanguage == NULL)
  1540     return 0;
  1541   return s_pfn_GetUserDefaultUILanguage ();
  1542 }
  1543 
  1544 
  1545 
  1546 /* Return 1 if P is a valid pointer to an object of size SIZE.  Return
  1547    0 if P is NOT a valid pointer.  Return -1 if we cannot validate P.
  1548 
  1549    This is called from alloc.c:valid_pointer_p.  */
  1550 int
  1551 w32_valid_pointer_p (void *p, int size)
  1552 {
  1553   SIZE_T done;
  1554   HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
  1555 
  1556   if (h)
  1557     {
  1558       unsigned char *buf = alloca (size);
  1559       int retval = ReadProcessMemory (h, p, buf, size, &done);
  1560 
  1561       CloseHandle (h);
  1562       return retval;
  1563     }
  1564   else
  1565     return -1;
  1566 }
  1567 
  1568 
  1569 
  1570 /* Here's an overview of how the Windows build supports file names
  1571    that cannot be encoded by the current system codepage.
  1572 
  1573    From the POV of Lisp and layers of C code above the functions here,
  1574    Emacs on Windows pretends that its file names are encoded in UTF-8;
  1575    see encode_file and decode_file on coding.c.  Any file name that is
  1576    passed as a unibyte string to C functions defined here is assumed
  1577    to be in UTF-8 encoding.  Any file name returned by functions
  1578    defined here must be in UTF-8 encoding, with only a few exceptions
  1579    reserved for a couple of special cases.  (Be sure to use
  1580    MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
  1581    as they can be much longer than MAX_PATH!)
  1582 
  1583    The UTF-8 encoded file names cannot be passed to system APIs, as
  1584    Windows does not support that.  Therefore, they are converted
  1585    either to UTF-16 or to the ANSI codepage, depending on the value of
  1586    w32-unicode-filenames, before calling any system APIs or CRT library
  1587    functions.  The default value of that variable is determined by the
  1588    OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
  1589    user can change that default (although I don't see why would she
  1590    want to).
  1591 
  1592    The 4 functions defined below, filename_to_utf16, filename_to_ansi,
  1593    filename_from_utf16, and filename_from_ansi, are the workhorses of
  1594    these conversions.  They rely on Windows native APIs
  1595    MultiByteToWideChar and WideCharToMultiByte; we cannot use
  1596    functions from coding.c here, because they allocate memory, which
  1597    is a bad idea on the level of libc, which is what the functions
  1598    here emulate.  (If you worry about performance due to constant
  1599    conversion back and forth from UTF-8 to UTF-16, then don't: first,
  1600    it was measured to take only a few microseconds on a not-so-fast
  1601    machine, and second, that's exactly what the ANSI APIs we used
  1602    before did anyway, because they are just thin wrappers around the
  1603    Unicode APIs.)
  1604 
  1605    The variables file-name-coding-system and default-file-name-coding-system
  1606    still exist, but are actually used only when a file name needs to
  1607    be converted to the ANSI codepage.  This happens all the time when
  1608    w32-unicode-filenames is nil, but can also happen from time to time
  1609    when it is t.  Otherwise, these variables have no effect on file-name
  1610    encoding when w32-unicode-filenames is t; this is similar to
  1611    selection-coding-system.
  1612 
  1613    This arrangement works very well, but it has a few gotchas and
  1614    limitations:
  1615 
  1616    . Lisp code that encodes or decodes file names manually should
  1617      normally use 'utf-8' as the coding-system on Windows,
  1618      disregarding file-name-coding-system.  This is a somewhat
  1619      unpleasant consequence, but it cannot be avoided.  Fortunately,
  1620      very few Lisp packages need to do that.
  1621 
  1622      More generally, passing to library functions (e.g., fopen or
  1623      opendir) file names already encoded in the ANSI codepage is
  1624      explicitly *verboten*, as all those functions, as shadowed and
  1625      emulated here, assume they will receive UTF-8 encoded file names.
  1626 
  1627      For the same reasons, no CRT function or Win32 API can be called
  1628      directly in Emacs sources, without either converting the file
  1629      names from UTF-8 to UTF-16 or ANSI codepage, or going through
  1630      some shadowing function defined here.
  1631 
  1632    . Environment variables stored in Vprocess_environment are encoded
  1633      in the ANSI codepage, so if getenv/egetenv is used for a variable
  1634      whose value is a file name or a list of directories, it needs to
  1635      be converted to UTF-8, before it is used as argument to functions
  1636      or decoded into a Lisp string.
  1637 
  1638    . File names passed to external libraries, like the image libraries
  1639      and GnuTLS, need special handling.  These libraries generally
  1640      don't support UTF-16 or UTF-8 file names, so they must get file
  1641      names encoded in the ANSI codepage.  To facilitate using these
  1642      libraries with file names that are not encodable in the ANSI
  1643      codepage, use the function ansi_encode_filename, which will try
  1644      to use the short 8+3 alias of a file name if that file name is
  1645      not encodable in the ANSI codepage.  See image.c and gnutls.c for
  1646      examples of how this should be done.
  1647 
  1648    . Running subprocesses in non-ASCII directories and with non-ASCII
  1649      file arguments is limited to the current codepage (even though
  1650      Emacs is perfectly capable of finding an executable program file
  1651      in a directory whose name cannot be encoded in the current
  1652      codepage).  This is because the command-line arguments are
  1653      encoded _before_ they get to the w32-specific level, and the
  1654      encoding is not known in advance (it doesn't have to be the
  1655      current ANSI codepage), so w32proc.c functions cannot re-encode
  1656      them in UTF-16.  This should be fixed, but will also require
  1657      changes in cmdproxy.  The current limitation is not terribly bad
  1658      anyway, since very few, if any, Windows console programs that are
  1659      likely to be invoked by Emacs support UTF-16 encoded command
  1660      lines.
  1661 
  1662    . For similar reasons, server.el and emacsclient are also limited
  1663      to the current ANSI codepage for now.
  1664 
  1665    . Emacs itself can only handle command-line arguments encoded in
  1666      the current codepage.
  1667 
  1668    . Turning on w32-unicode-filename on Windows 9X (if it at all
  1669      works) requires UNICOWS.DLL, which is thus a requirement even in
  1670      non-GUI sessions, something that we previously avoided.  */
  1671 
  1672 
  1673 
  1674 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
  1675    codepage defined by file-name-coding-system.  */
  1676 
  1677 /* Current codepage for encoding file names.  */
  1678 static int file_name_codepage;
  1679 
  1680 /* Initialize the codepage used for decoding file names.  This is
  1681    needed to undo the value recorded during dumping, which might not
  1682    be correct when we run the dumped Emacs.  */
  1683 void
  1684 w32_init_file_name_codepage (void)
  1685 {
  1686   file_name_codepage = CP_ACP;
  1687   w32_ansi_code_page = CP_ACP;
  1688 }
  1689 
  1690 /* Produce a Windows ANSI codepage suitable for encoding file names.
  1691    Return the information about that codepage in CP_INFO.  */
  1692 int
  1693 codepage_for_filenames (CPINFO *cp_info)
  1694 {
  1695   /* A simple cache to avoid calling GetCPInfo every time we need to
  1696      encode/decode a file name.  The file-name encoding is not
  1697      supposed to be changed too frequently, if ever.  */
  1698   static Lisp_Object last_file_name_encoding;
  1699   static CPINFO cp;
  1700   Lisp_Object current_encoding;
  1701 
  1702   current_encoding = Vfile_name_coding_system;
  1703   if (NILP (current_encoding))
  1704     current_encoding = Vdefault_file_name_coding_system;
  1705 
  1706   if (!EQ (last_file_name_encoding, current_encoding)
  1707       || NILP (last_file_name_encoding))
  1708     {
  1709       /* Default to the current ANSI codepage.  */
  1710       file_name_codepage = w32_ansi_code_page;
  1711 
  1712       if (!NILP (current_encoding))
  1713         {
  1714           char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
  1715           char *cp = NULL, *end;
  1716           int cpnum;
  1717 
  1718           if (strncmp (cpname, "cp", 2) == 0)
  1719             cp = cpname + 2;
  1720           else if (strncmp (cpname, "windows-", 8) == 0)
  1721             cp = cpname + 8;
  1722 
  1723           if (cp)
  1724             {
  1725               end = cp;
  1726               cpnum = strtol (cp, &end, 10);
  1727               if (cpnum && *end == '\0' && end - cp >= 2)
  1728                 file_name_codepage = cpnum;
  1729             }
  1730         }
  1731 
  1732       if (!file_name_codepage)
  1733         file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
  1734 
  1735       if (!GetCPInfo (file_name_codepage, &cp))
  1736         {
  1737           file_name_codepage = CP_ACP;
  1738           if (!GetCPInfo (file_name_codepage, &cp))
  1739             emacs_abort ();
  1740         }
  1741 
  1742       /* Cache the new value.  */
  1743       last_file_name_encoding = current_encoding;
  1744     }
  1745   if (cp_info)
  1746     *cp_info = cp;
  1747 
  1748   return file_name_codepage;
  1749 }
  1750 
  1751 int
  1752 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
  1753 {
  1754   int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
  1755                                      -1, fn_out, MAX_PATH);
  1756 
  1757   if (!result)
  1758     {
  1759       DWORD err = GetLastError ();
  1760 
  1761       switch (err)
  1762         {
  1763         case ERROR_INVALID_FLAGS:
  1764         case ERROR_INVALID_PARAMETER:
  1765           errno = EINVAL;
  1766           break;
  1767         case ERROR_INSUFFICIENT_BUFFER:
  1768         case ERROR_NO_UNICODE_TRANSLATION:
  1769         default:
  1770           errno = ENOENT;
  1771           break;
  1772         }
  1773       return -1;
  1774     }
  1775   return 0;
  1776 }
  1777 
  1778 int
  1779 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
  1780 {
  1781   int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
  1782                                      fn_out, MAX_UTF8_PATH, NULL, NULL);
  1783 
  1784   if (!result)
  1785     {
  1786       DWORD err = GetLastError ();
  1787 
  1788       switch (err)
  1789         {
  1790         case ERROR_INVALID_FLAGS:
  1791         case ERROR_INVALID_PARAMETER:
  1792           errno = EINVAL;
  1793           break;
  1794         case ERROR_INSUFFICIENT_BUFFER:
  1795         case ERROR_NO_UNICODE_TRANSLATION:
  1796         default:
  1797           errno = ENOENT;
  1798           break;
  1799         }
  1800       return -1;
  1801     }
  1802   return 0;
  1803 }
  1804 
  1805 int
  1806 filename_to_ansi (const char *fn_in, char *fn_out)
  1807 {
  1808   wchar_t fn_utf16[MAX_PATH];
  1809 
  1810   if (filename_to_utf16 (fn_in, fn_utf16) == 0)
  1811     {
  1812       int result;
  1813       int codepage = codepage_for_filenames (NULL);
  1814 
  1815       result  = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
  1816                                       fn_out, MAX_PATH, NULL, NULL);
  1817       if (!result)
  1818         {
  1819           DWORD err = GetLastError ();
  1820 
  1821           switch (err)
  1822             {
  1823             case ERROR_INVALID_FLAGS:
  1824             case ERROR_INVALID_PARAMETER:
  1825               errno = EINVAL;
  1826               break;
  1827             case ERROR_INSUFFICIENT_BUFFER:
  1828             case ERROR_NO_UNICODE_TRANSLATION:
  1829             default:
  1830               errno = ENOENT;
  1831               break;
  1832             }
  1833           return -1;
  1834         }
  1835       return 0;
  1836     }
  1837   return -1;
  1838 }
  1839 
  1840 int
  1841 filename_from_ansi (const char *fn_in, char *fn_out)
  1842 {
  1843   wchar_t fn_utf16[MAX_PATH];
  1844   int codepage = codepage_for_filenames (NULL);
  1845   int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
  1846                                      -1, fn_utf16, MAX_PATH);
  1847 
  1848   if (!result)
  1849     {
  1850       DWORD err = GetLastError ();
  1851 
  1852       switch (err)
  1853         {
  1854         case ERROR_INVALID_FLAGS:
  1855         case ERROR_INVALID_PARAMETER:
  1856           errno = EINVAL;
  1857           break;
  1858         case ERROR_INSUFFICIENT_BUFFER:
  1859         case ERROR_NO_UNICODE_TRANSLATION:
  1860         default:
  1861           errno = ENOENT;
  1862           break;
  1863         }
  1864       return -1;
  1865     }
  1866   return filename_from_utf16 (fn_utf16, fn_out);
  1867 }
  1868 
  1869 
  1870 
  1871 /* The directory where we started, in UTF-8. */
  1872 static char startup_dir[MAX_UTF8_PATH];
  1873 
  1874 /* Get the current working directory.  The caller must arrange for CWD
  1875    to be allocated with enough space to hold a 260-char directory name
  1876    in UTF-8.  IOW, the space should be at least MAX_UTF8_PATH bytes.  */
  1877 static void
  1878 w32_get_current_directory (char *cwd)
  1879 {
  1880   /* FIXME: Do we need to resolve possible symlinks in startup_dir?
  1881      Does it matter anywhere in Emacs?  */
  1882   if (w32_unicode_filenames)
  1883     {
  1884       wchar_t wstartup_dir[MAX_PATH];
  1885 
  1886       if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
  1887         emacs_abort ();
  1888       filename_from_utf16 (wstartup_dir, cwd);
  1889     }
  1890   else
  1891     {
  1892       char astartup_dir[MAX_PATH];
  1893 
  1894       if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
  1895         emacs_abort ();
  1896       filename_from_ansi (astartup_dir, cwd);
  1897     }
  1898 }
  1899 
  1900 /* For external callers.  Used by 'main' in emacs.c.  */
  1901 void
  1902 w32_init_current_directory (void)
  1903 {
  1904   w32_get_current_directory (startup_dir);
  1905 }
  1906 
  1907 /* Return the original directory where Emacs started.  */
  1908 char *
  1909 getcwd (char *dir, int dirsize)
  1910 {
  1911   if (!dirsize)
  1912     {
  1913       errno = EINVAL;
  1914       return NULL;
  1915     }
  1916   if (dirsize <= strlen (startup_dir))
  1917     {
  1918       errno = ERANGE;
  1919       return NULL;
  1920     }
  1921 #if 0
  1922   if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
  1923     return dir;
  1924   return NULL;
  1925 #else
  1926   /* Emacs doesn't actually change directory itself, it stays in the
  1927      same directory where it was started.  */
  1928   strcpy (dir, startup_dir);
  1929   return dir;
  1930 #endif
  1931 }
  1932 
  1933 /* Emulate getloadavg.  */
  1934 
  1935 struct load_sample {
  1936   time_t sample_time;
  1937   ULONGLONG idle;
  1938   ULONGLONG kernel;
  1939   ULONGLONG user;
  1940 };
  1941 
  1942 /* Number of processors on this machine.  */
  1943 static unsigned num_of_processors;
  1944 
  1945 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
  1946 static struct load_sample samples[16*60];
  1947 static int first_idx = -1, last_idx = -1;
  1948 static int max_idx = ARRAYELTS (samples);
  1949 
  1950 static int
  1951 buf_next (int from)
  1952 {
  1953   int next_idx = from + 1;
  1954 
  1955   if (next_idx >= max_idx)
  1956     next_idx = 0;
  1957 
  1958   return next_idx;
  1959 }
  1960 
  1961 static int
  1962 buf_prev (int from)
  1963 {
  1964   int prev_idx = from - 1;
  1965 
  1966   if (prev_idx < 0)
  1967     prev_idx = max_idx - 1;
  1968 
  1969   return prev_idx;
  1970 }
  1971 
  1972 unsigned
  1973 w32_get_nproc (void)
  1974 {
  1975   SYSTEM_INFO sysinfo;
  1976 
  1977   /* Initialize the number of processors on this machine.  */
  1978   if (num_of_processors <= 0)
  1979     {
  1980       get_native_system_info (&sysinfo);
  1981       num_of_processors = sysinfo.dwNumberOfProcessors;
  1982       if (num_of_processors <= 0)
  1983         {
  1984           GetSystemInfo (&sysinfo);
  1985           num_of_processors = sysinfo.dwNumberOfProcessors;
  1986         }
  1987       if (num_of_processors <= 0)
  1988         num_of_processors = 1;
  1989     }
  1990   return num_of_processors;
  1991 }
  1992 
  1993 /* Emulate Gnulib's 'num_processors'.  We cannot use the Gnulib
  1994    version because it unconditionally calls APIs that aren't available
  1995    on old MS-Windows versions.  */
  1996 unsigned long
  1997 num_processors (enum nproc_query query)
  1998 {
  1999   /* We ignore QUERY.  */
  2000   return w32_get_nproc ();
  2001 }
  2002 
  2003 static void
  2004 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
  2005 {
  2006   FILETIME ft_idle, ft_user, ft_kernel;
  2007 
  2008   (void) w32_get_nproc ();
  2009 
  2010   /* TODO: Take into account threads that are ready to run, by
  2011      sampling the "\System\Processor Queue Length" performance
  2012      counter.  The code below accounts only for threads that are
  2013      actually running.  */
  2014 
  2015   if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
  2016     {
  2017       ULARGE_INTEGER uidle, ukernel, uuser;
  2018 
  2019       memcpy (&uidle, &ft_idle, sizeof (ft_idle));
  2020       memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
  2021       memcpy (&uuser, &ft_user, sizeof (ft_user));
  2022       *idle = uidle.QuadPart;
  2023       *kernel = ukernel.QuadPart;
  2024       *user = uuser.QuadPart;
  2025     }
  2026   else
  2027     {
  2028       *idle = 0;
  2029       *kernel = 0;
  2030       *user = 0;
  2031     }
  2032 }
  2033 
  2034 /* Produce the load average for a given time interval, using the
  2035    samples in the samples[] array.  WHICH can be 0, 1, or 2, meaning
  2036    1-minute, 5-minute, or 15-minute average, respectively. */
  2037 static double
  2038 getavg (int which)
  2039 {
  2040   double retval = -1.0;
  2041   double tdiff;
  2042   int idx;
  2043   double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
  2044   time_t now = samples[last_idx].sample_time;
  2045 
  2046   if (first_idx != last_idx)
  2047     {
  2048       for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
  2049         {
  2050           tdiff = difftime (now, samples[idx].sample_time);
  2051           if (tdiff >= span - 2*DBL_EPSILON*now)
  2052             {
  2053               long double sys =
  2054                 samples[last_idx].kernel + samples[last_idx].user
  2055                 - (samples[idx].kernel + samples[idx].user);
  2056               long double idl = samples[last_idx].idle - samples[idx].idle;
  2057 
  2058               retval = (1.0 - idl / sys) * num_of_processors;
  2059               break;
  2060             }
  2061           if (idx == first_idx)
  2062             break;
  2063         }
  2064     }
  2065 
  2066   return retval;
  2067 }
  2068 
  2069 int
  2070 getloadavg (double loadavg[], int nelem)
  2071 {
  2072   int elem;
  2073   ULONGLONG idle, kernel, user;
  2074   time_t now = time (NULL);
  2075 
  2076   /* If system time jumped back for some reason, delete all samples
  2077      whose time is later than the current wall-clock time.  This
  2078      prevents load average figures from becoming frozen for prolonged
  2079      periods of time, when system time is reset backwards.  */
  2080   if (last_idx >= 0)
  2081     {
  2082       while (difftime (now, samples[last_idx].sample_time) < -1.0)
  2083         {
  2084           if (last_idx == first_idx)
  2085             {
  2086               first_idx = last_idx = -1;
  2087               break;
  2088             }
  2089           last_idx = buf_prev (last_idx);
  2090         }
  2091     }
  2092 
  2093   /* Store another sample.  We ignore samples that are less than 1 sec
  2094      apart.  */
  2095   if (last_idx < 0
  2096       || (difftime (now, samples[last_idx].sample_time)
  2097           >= 1.0 - 2*DBL_EPSILON*now))
  2098     {
  2099       sample_system_load (&idle, &kernel, &user);
  2100       last_idx = buf_next (last_idx);
  2101       samples[last_idx].sample_time = now;
  2102       samples[last_idx].idle = idle;
  2103       samples[last_idx].kernel = kernel;
  2104       samples[last_idx].user = user;
  2105       /* If the buffer has more that 15 min worth of samples, discard
  2106          the old ones.  */
  2107       if (first_idx == -1)
  2108         first_idx = last_idx;
  2109       while (first_idx != last_idx
  2110              && (difftime (now, samples[first_idx].sample_time)
  2111                  >= 15.0*60 + 2*DBL_EPSILON*now))
  2112         first_idx = buf_next (first_idx);
  2113     }
  2114 
  2115   for (elem = 0; elem < nelem; elem++)
  2116     {
  2117       double avg = getavg (elem);
  2118 
  2119       if (avg < 0)
  2120         break;
  2121       loadavg[elem] = avg;
  2122     }
  2123 
  2124   /* Always return at least one element, otherwise load-average
  2125      returns nil, and Lisp programs might decide we cannot measure
  2126      system load.  For example, jit-lock-stealth-load's defcustom
  2127      might decide that feature is "unsupported".  */
  2128   if (elem == 0)
  2129     loadavg[elem++] = 0.09;     /* < display-time-load-average-threshold */
  2130 
  2131   return elem;
  2132 }
  2133 
  2134 /* Emulate getpwuid, getpwnam and others.  */
  2135 
  2136 #define PASSWD_FIELD_SIZE 256
  2137 
  2138 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
  2139 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
  2140 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
  2141 static char dflt_passwd_dir[MAX_UTF8_PATH];
  2142 static char dflt_passwd_shell[MAX_UTF8_PATH];
  2143 
  2144 static struct passwd dflt_passwd =
  2145 {
  2146   dflt_passwd_name,
  2147   dflt_passwd_passwd,
  2148   0,
  2149   0,
  2150   0,
  2151   dflt_passwd_gecos,
  2152   dflt_passwd_dir,
  2153   dflt_passwd_shell,
  2154 };
  2155 
  2156 static char dflt_group_name[GNLEN+1];
  2157 
  2158 static struct group dflt_group =
  2159 {
  2160   /* When group information is not available, we return this as the
  2161      group for all files.  */
  2162   dflt_group_name,
  2163   0,
  2164 };
  2165 
  2166 unsigned
  2167 getuid (void)
  2168 {
  2169   return dflt_passwd.pw_uid;
  2170 }
  2171 
  2172 unsigned
  2173 geteuid (void)
  2174 {
  2175   /* I could imagine arguing for checking to see whether the user is
  2176      in the Administrators group and returning a UID of 0 for that
  2177      case, but I don't know how wise that would be in the long run.  */
  2178   return getuid ();
  2179 }
  2180 
  2181 unsigned
  2182 getgid (void)
  2183 {
  2184   return dflt_passwd.pw_gid;
  2185 }
  2186 
  2187 unsigned
  2188 getegid (void)
  2189 {
  2190   return getgid ();
  2191 }
  2192 
  2193 struct passwd *
  2194 getpwuid (unsigned uid)
  2195 {
  2196   if (uid == dflt_passwd.pw_uid)
  2197     return &dflt_passwd;
  2198   return NULL;
  2199 }
  2200 
  2201 struct group *
  2202 getgrgid (gid_t gid)
  2203 {
  2204   if (gid == dflt_passwd.pw_gid)
  2205     return &dflt_group;
  2206   return NULL;
  2207 }
  2208 
  2209 struct passwd *
  2210 getpwnam (char *name)
  2211 {
  2212   struct passwd *pw;
  2213 
  2214   pw = getpwuid (getuid ());
  2215   if (!pw)
  2216     return pw;
  2217 
  2218   if (xstrcasecmp (name, pw->pw_name))
  2219     {
  2220       /* Mimic what init_editfns does with these environment
  2221          variables, so that the likes of ~USER is recognized by
  2222          expand-file-name even if $LOGNAME gives a name different from
  2223          the real username produced by the process token.  */
  2224       char *logname = getenv ("LOGNAME");
  2225       char *username = getenv ("USERNAME");
  2226       if ((logname || username)
  2227           && xstrcasecmp (name, logname ? logname : username) == 0)
  2228         {
  2229           static struct passwd alias_user;
  2230           static char alias_name[PASSWD_FIELD_SIZE];
  2231 
  2232           memcpy (&alias_user, &dflt_passwd, sizeof dflt_passwd);
  2233           alias_name[0] = '\0';
  2234           strncat (alias_name, logname ? logname : username,
  2235                    PASSWD_FIELD_SIZE - 1);
  2236           alias_user.pw_name = alias_name;
  2237           pw = &alias_user;
  2238         }
  2239       else
  2240         return NULL;
  2241     }
  2242 
  2243   return pw;
  2244 }
  2245 
  2246 static void
  2247 init_user_info (void)
  2248 {
  2249   /* Find the user's real name by opening the process token and
  2250      looking up the name associated with the user-sid in that token.
  2251 
  2252      Use the relative portion of the identifier authority value from
  2253      the user-sid as the user id value (same for group id using the
  2254      primary group sid from the process token). */
  2255 
  2256   char         uname[UNLEN+1], gname[GNLEN+1], domain[1025];
  2257   DWORD        ulength = sizeof (uname), dlength = sizeof (domain), needed;
  2258   DWORD        glength = sizeof (gname);
  2259   HANDLE       token = NULL;
  2260   SID_NAME_USE user_type;
  2261   unsigned char *buf = NULL;
  2262   DWORD        blen = 0;
  2263   TOKEN_USER   user_token;
  2264   TOKEN_PRIMARY_GROUP group_token;
  2265   BOOL         result;
  2266 
  2267   result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
  2268   if (result)
  2269     {
  2270       result = get_token_information (token, TokenUser, NULL, 0, &blen);
  2271       if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
  2272         {
  2273           buf = xmalloc (blen);
  2274           result = get_token_information (token, TokenUser,
  2275                                           (LPVOID)buf, blen, &needed);
  2276           if (result)
  2277             {
  2278               memcpy (&user_token, buf, sizeof (user_token));
  2279               result = lookup_account_sid (NULL, user_token.User.Sid,
  2280                                            uname, &ulength,
  2281                                            domain, &dlength, &user_type);
  2282             }
  2283         }
  2284       else
  2285         result = FALSE;
  2286     }
  2287   if (result)
  2288     {
  2289       strcpy (dflt_passwd.pw_name, uname);
  2290       /* Determine a reasonable uid value.  */
  2291       if (xstrcasecmp ("administrator", uname) == 0)
  2292         {
  2293           dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
  2294           dflt_passwd.pw_gid = 513; /* well-known None gid */
  2295         }
  2296       else
  2297         {
  2298           /* Use the last sub-authority value of the RID, the relative
  2299              portion of the SID, as user/group ID. */
  2300           dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
  2301 
  2302           /* Get group id and name.  */
  2303           result = get_token_information (token, TokenPrimaryGroup,
  2304                                           (LPVOID)buf, blen, &needed);
  2305           if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
  2306             {
  2307               buf = xrealloc (buf, blen = needed);
  2308               result = get_token_information (token, TokenPrimaryGroup,
  2309                                               (LPVOID)buf, blen, &needed);
  2310             }
  2311           if (result)
  2312             {
  2313               memcpy (&group_token, buf, sizeof (group_token));
  2314               dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
  2315               dlength = sizeof (domain);
  2316               /* If we can get at the real Primary Group name, use that.
  2317                  Otherwise, the default group name was already set to
  2318                  "None" in globals_of_w32.  */
  2319               if (lookup_account_sid (NULL, group_token.PrimaryGroup,
  2320                                       gname, &glength, NULL, &dlength,
  2321                                       &user_type))
  2322                 strcpy (dflt_group_name, gname);
  2323             }
  2324           else
  2325             dflt_passwd.pw_gid = dflt_passwd.pw_uid;
  2326         }
  2327     }
  2328   /* If security calls are not supported (presumably because we
  2329      are running under Windows 9X), fallback to this: */
  2330   else if (GetUserName (uname, &ulength))
  2331     {
  2332       strcpy (dflt_passwd.pw_name, uname);
  2333       if (xstrcasecmp ("administrator", uname) == 0)
  2334         dflt_passwd.pw_uid = 0;
  2335       else
  2336         dflt_passwd.pw_uid = 123;
  2337       dflt_passwd.pw_gid = dflt_passwd.pw_uid;
  2338     }
  2339   else
  2340     {
  2341       strcpy (dflt_passwd.pw_name, "unknown");
  2342       dflt_passwd.pw_uid = 123;
  2343       dflt_passwd.pw_gid = 123;
  2344     }
  2345   dflt_group.gr_gid = dflt_passwd.pw_gid;
  2346 
  2347   /* Set dir and shell from environment variables. */
  2348   if (w32_unicode_filenames)
  2349     {
  2350       wchar_t *home = _wgetenv (L"HOME");
  2351       wchar_t *shell = _wgetenv (L"SHELL");
  2352 
  2353       /* Ensure HOME and SHELL are defined. */
  2354       if (home == NULL)
  2355         emacs_abort ();
  2356       if (shell == NULL)
  2357         emacs_abort ();
  2358       filename_from_utf16 (home, dflt_passwd.pw_dir);
  2359       filename_from_utf16 (shell, dflt_passwd.pw_shell);
  2360     }
  2361   else
  2362     {
  2363       char *home = getenv ("HOME");
  2364       char *shell = getenv ("SHELL");
  2365 
  2366       if (home == NULL)
  2367         emacs_abort ();
  2368       if (shell == NULL)
  2369         emacs_abort ();
  2370       filename_from_ansi (home, dflt_passwd.pw_dir);
  2371       filename_from_ansi (shell, dflt_passwd.pw_shell);
  2372     }
  2373 
  2374   xfree (buf);
  2375   if (token)
  2376     CloseHandle (token);
  2377 }
  2378 
  2379 static HCRYPTPROV w32_crypto_hprov;
  2380 static int
  2381 w32_init_crypt_random (void)
  2382 {
  2383   if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
  2384                             CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
  2385     {
  2386       DebPrint (("CryptAcquireContext failed with error %x\n",
  2387                  GetLastError ()));
  2388       w32_crypto_hprov = 0;
  2389       return -1;
  2390     }
  2391   return 0;
  2392 }
  2393 
  2394 int
  2395 w32_init_random (void *buf, ptrdiff_t buflen)
  2396 {
  2397   if (!w32_crypto_hprov)
  2398     w32_init_crypt_random ();
  2399   if (w32_crypto_hprov)
  2400     {
  2401       if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
  2402         return 0;
  2403     }
  2404   return -1;
  2405 }
  2406 
  2407 /* MS-Windows 'rand' produces separate identical series for each
  2408    thread, so we replace it with our version.  */
  2409 
  2410 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
  2411    Generator, by B.A. Wichmann, I.D. Hill.  AS, v31, No. 2 (1982).  */
  2412 static int ix = 3172, iy = 9814, iz = 20125;
  2413 #define RAND_MAX_X  30269
  2414 #define RAND_MAX_Y  30307
  2415 #define RAND_MAX_Z  30323
  2416 
  2417 static int
  2418 rand_as183 (void)
  2419 {
  2420   ix = (171 * ix) % RAND_MAX_X;
  2421   iy = (172 * iy) % RAND_MAX_Y;
  2422   iz = (170 * iz) % RAND_MAX_Z;
  2423 
  2424   return (ix + iy + iz) & 0x7fff;
  2425 }
  2426 
  2427 int
  2428 random (void)
  2429 {
  2430   /* rand_as183 () gives us 15 random bits...hack together 30 bits for
  2431      Emacs with 32-bit EMACS_INT, and at least 31 bit for wider EMACS_INT.  */
  2432 #if EMACS_INT_MAX > INT_MAX
  2433   return ((rand_as183 () << 30) | (rand_as183 () << 15) | rand_as183 ());
  2434 #else
  2435   return ((rand_as183 () << 15) | rand_as183 ());
  2436 #endif
  2437 }
  2438 
  2439 void
  2440 srandom (int seed)
  2441 {
  2442   srand (seed);
  2443   ix = rand () % RAND_MAX_X;
  2444   iy = rand () % RAND_MAX_Y;
  2445   iz = rand () % RAND_MAX_Z;
  2446 }
  2447 
  2448 /* Emulate explicit_bzero.  This is to avoid using the Gnulib version,
  2449    because it calls SecureZeroMemory at will, disregarding systems
  2450    older than Windows XP, which didn't have that function.  We want to
  2451    avoid having that function as dependency in builds that need to
  2452    support systems older than Windows XP, otherwise Emacs will refuse
  2453    to start on those systems.  */
  2454 void
  2455 explicit_bzero (void *buf, size_t len)
  2456 {
  2457 #if _WIN32_WINNT >= 0x0501
  2458   /* We are compiling for XP or newer, most probably with MinGW64.
  2459      We can use SecureZeroMemory.  */
  2460   SecureZeroMemory (buf, len);
  2461 #else
  2462   memset (buf, 0, len);
  2463   /* Compiler barrier.  */
  2464   asm volatile ("" ::: "memory");
  2465 #endif
  2466 }
  2467 
  2468 /* Return the maximum length in bytes of a multibyte character
  2469    sequence encoded in the current ANSI codepage.  This is required to
  2470    correctly walk the encoded file names one character at a time.  */
  2471 static int
  2472 max_filename_mbslen (void)
  2473 {
  2474   CPINFO cp_info;
  2475 
  2476   codepage_for_filenames (&cp_info);
  2477   return cp_info.MaxCharSize;
  2478 }
  2479 
  2480 /* Normalize filename by converting in-place all of its path
  2481    separators to the separator specified by PATH_SEP.  */
  2482 
  2483 static void
  2484 normalize_filename (register char *fp, char path_sep)
  2485 {
  2486   char *p2;
  2487 
  2488   /* Always lower-case drive letters a-z, even if the filesystem
  2489      preserves case in filenames.
  2490      This is so filenames can be compared by string comparison
  2491      functions that are case-sensitive.  Even case-preserving filesystems
  2492      do not distinguish case in drive letters.  */
  2493   p2 = fp + 1;
  2494 
  2495   if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
  2496     {
  2497       *fp += 'a' - 'A';
  2498       fp += 2;
  2499     }
  2500 
  2501   while (*fp)
  2502     {
  2503       if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
  2504         *fp = path_sep;
  2505       fp++;
  2506     }
  2507 }
  2508 
  2509 /* Destructively turn backslashes into slashes.  */
  2510 void
  2511 dostounix_filename (register char *p)
  2512 {
  2513   normalize_filename (p, '/');
  2514 }
  2515 
  2516 /* Destructively turn slashes into backslashes.  */
  2517 void
  2518 unixtodos_filename (register char *p)
  2519 {
  2520   normalize_filename (p, '\\');
  2521 }
  2522 
  2523 /* Remove all CR's that are followed by a LF.
  2524    (From msdos.c...probably should figure out a way to share it,
  2525    although this code isn't going to ever change.)  */
  2526 static int
  2527 crlf_to_lf (register int n, register char *buf)
  2528 {
  2529   unsigned char *np = (unsigned char *)buf;
  2530   unsigned char *startp = np;
  2531   char *endp = buf + n;
  2532 
  2533   if (n == 0)
  2534     return n;
  2535   while (buf < endp - 1)
  2536     {
  2537       if (*buf == 0x0d)
  2538         {
  2539           if (*(++buf) != 0x0a)
  2540             *np++ = 0x0d;
  2541         }
  2542       else
  2543         *np++ = *buf++;
  2544     }
  2545   if (buf < endp)
  2546     *np++ = *buf++;
  2547   return np - startp;
  2548 }
  2549 
  2550 /* Parse the root part of file name, if present.  Return length and
  2551     optionally store pointer to char after root.  */
  2552 static int
  2553 parse_root (const char * name, const char ** pPath)
  2554 {
  2555   const char * start = name;
  2556 
  2557   if (name == NULL)
  2558     return 0;
  2559 
  2560   /* find the root name of the volume if given */
  2561   if (isalpha (name[0]) && name[1] == ':')
  2562     {
  2563       /* skip past drive specifier */
  2564       name += 2;
  2565       if (IS_DIRECTORY_SEP (name[0]))
  2566         name++;
  2567     }
  2568   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
  2569     {
  2570       int slashes = 2;
  2571 
  2572       name += 2;
  2573       do
  2574         {
  2575           if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
  2576             break;
  2577           name++;
  2578         }
  2579       while ( *name );
  2580       if (IS_DIRECTORY_SEP (name[0]))
  2581         name++;
  2582     }
  2583 
  2584   if (pPath)
  2585     *pPath = name;
  2586 
  2587   return name - start;
  2588 }
  2589 
  2590 /* Get long base name for name; name is assumed to be absolute.  */
  2591 static int
  2592 get_long_basename (char * name, char * buf, int size)
  2593 {
  2594   HANDLE dir_handle = INVALID_HANDLE_VALUE;
  2595   char fname_utf8[MAX_UTF8_PATH];
  2596   int len = 0;
  2597   int cstatus = -1;
  2598 
  2599   /* Must be valid filename, no wild cards or other invalid characters.  */
  2600   if (strpbrk (name, "*?|<>\""))
  2601     return 0;
  2602 
  2603   if (w32_unicode_filenames)
  2604     {
  2605       wchar_t fname_utf16[MAX_PATH];
  2606       WIN32_FIND_DATAW find_data_wide;
  2607 
  2608       filename_to_utf16 (name, fname_utf16);
  2609       dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
  2610       if (dir_handle != INVALID_HANDLE_VALUE)
  2611         cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
  2612     }
  2613   else
  2614     {
  2615       char fname_ansi[MAX_PATH];
  2616       WIN32_FIND_DATAA find_data_ansi;
  2617 
  2618       filename_to_ansi (name, fname_ansi);
  2619       /* If the ANSI name includes ? characters, it is not encodable
  2620          in the ANSI codepage.  In that case, we deliver the question
  2621          marks to the caller; calling FindFirstFileA in this case
  2622          could return some unrelated file name in the same
  2623          directory.  */
  2624       if (_mbspbrk (fname_ansi, "?"))
  2625         {
  2626           /* Find the basename of fname_ansi.  */
  2627           char *p = strrchr (fname_ansi, '\\');
  2628 
  2629           if (!p)
  2630             p = fname_ansi;
  2631           else
  2632             p++;
  2633           cstatus = filename_from_ansi (p, fname_utf8);
  2634         }
  2635       else
  2636         {
  2637           dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
  2638           if (dir_handle != INVALID_HANDLE_VALUE)
  2639             cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
  2640         }
  2641     }
  2642 
  2643   if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
  2644     memcpy (buf, fname_utf8, len + 1);
  2645   else
  2646     len = 0;
  2647 
  2648   if (dir_handle != INVALID_HANDLE_VALUE)
  2649     FindClose (dir_handle);
  2650 
  2651   return len;
  2652 }
  2653 
  2654 /* Get long name for file, if possible (assumed to be absolute).  */
  2655 BOOL
  2656 w32_get_long_filename (const char * name, char * buf, int size)
  2657 {
  2658   char * o = buf;
  2659   char * p;
  2660   const char * q;
  2661   char full[ MAX_UTF8_PATH ];
  2662   int len;
  2663 
  2664   len = strlen (name);
  2665   if (len >= MAX_UTF8_PATH)
  2666     return FALSE;
  2667 
  2668   /* Use local copy for destructive modification.  */
  2669   memcpy (full, name, len+1);
  2670   unixtodos_filename (full);
  2671 
  2672   /* Copy root part verbatim.  */
  2673   len = parse_root (full, (const char **)&p);
  2674   memcpy (o, full, len);
  2675   o += len;
  2676   *o = '\0';
  2677   size -= len;
  2678 
  2679   while (p != NULL && *p)
  2680     {
  2681       q = p;
  2682       p = strchr (q, '\\');
  2683       if (p) *p = '\0';
  2684       len = get_long_basename (full, o, size);
  2685       if (len > 0)
  2686         {
  2687           o += len;
  2688           size -= len;
  2689           if (p != NULL)
  2690             {
  2691               *p++ = '\\';
  2692               if (size < 2)
  2693                 return FALSE;
  2694               *o++ = '\\';
  2695               size--;
  2696               *o = '\0';
  2697             }
  2698         }
  2699       else
  2700         return FALSE;
  2701     }
  2702 
  2703   return TRUE;
  2704 }
  2705 
  2706 unsigned int
  2707 w32_get_short_filename (const char * name, char * buf, int size)
  2708 {
  2709   if (w32_unicode_filenames)
  2710     {
  2711       wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
  2712       unsigned int retval;
  2713 
  2714       filename_to_utf16 (name, name_utf16);
  2715       retval = GetShortPathNameW (name_utf16, short_name, size);
  2716       if (retval && retval < size)
  2717         filename_from_utf16 (short_name, buf);
  2718       return retval;
  2719     }
  2720   else
  2721     {
  2722       char name_ansi[MAX_PATH];
  2723 
  2724       filename_to_ansi (name, name_ansi);
  2725       return GetShortPathNameA (name_ansi, buf, size);
  2726     }
  2727 }
  2728 
  2729 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
  2730    MS-Windows ANSI codepage.  If FILENAME includes characters not
  2731    supported by the ANSI codepage, return the 8+3 alias of FILENAME,
  2732    if it exists.  This is needed because the w32 build wants to
  2733    support file names outside of the system locale, but image
  2734    libraries typically don't support wide (a.k.a. "Unicode") APIs
  2735    required for that.  */
  2736 
  2737 Lisp_Object
  2738 ansi_encode_filename (Lisp_Object filename)
  2739 {
  2740   Lisp_Object encoded_filename;
  2741   char fname[MAX_PATH];
  2742 
  2743   filename_to_ansi (SSDATA (filename), fname);
  2744   if (_mbspbrk (fname, "?"))
  2745     {
  2746       char shortname[MAX_PATH];
  2747 
  2748       if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
  2749         {
  2750           dostounix_filename (shortname);
  2751           encoded_filename = build_string (shortname);
  2752         }
  2753       else
  2754         encoded_filename = build_unibyte_string (fname);
  2755     }
  2756   else
  2757     encoded_filename = build_unibyte_string (fname);
  2758   return encoded_filename;
  2759 }
  2760 
  2761 static int
  2762 is_unc_volume (const char *filename)
  2763 {
  2764   const char *ptr = filename;
  2765 
  2766   if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
  2767     return 0;
  2768 
  2769   if (strpbrk (ptr + 2, "*?|<>\"\\/"))
  2770     return 0;
  2771 
  2772   return 1;
  2773 }
  2774 
  2775 /* Emulate the Posix unsetenv.  */
  2776 int
  2777 unsetenv (const char *name)
  2778 {
  2779   char *var;
  2780   size_t name_len;
  2781 
  2782   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
  2783     {
  2784       errno = EINVAL;
  2785       return -1;
  2786     }
  2787   name_len = strlen (name);
  2788   /* MS docs says an environment variable cannot be longer than 32K.  */
  2789   if (name_len > 32767)
  2790     {
  2791       errno = ENOMEM;
  2792       return 0;
  2793     }
  2794   /* It is safe to use 'alloca' with 32K size, since the stack is at
  2795      least 2MB, and we set it to 8MB in the link command line.  */
  2796   var = alloca (name_len + 2);
  2797   memcpy (var, name, name_len);
  2798   var[name_len++] = '=';
  2799   var[name_len] = '\0';
  2800   return _putenv (var);
  2801 }
  2802 
  2803 /* MS _putenv doesn't support removing a variable when the argument
  2804    does not include the '=' character, so we fix that here.  */
  2805 int
  2806 sys_putenv (char *str)
  2807 {
  2808   const char *const name_end = strchr (str, '=');
  2809 
  2810   if (name_end == NULL)
  2811     {
  2812       /* Remove the variable from the environment.  */
  2813       return unsetenv (str);
  2814     }
  2815 
  2816   if (strncmp (str, "TZ=<", 4) == 0)
  2817     {
  2818       /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
  2819          abbreviation syntax.  Convert to POSIX.1-1988 syntax if possible,
  2820          and to the undocumented placeholder "ZZZ" otherwise.  */
  2821       bool supported_abbr = true;
  2822       for (char *p = str + 4; *p; p++)
  2823         {
  2824           if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
  2825             supported_abbr = false;
  2826           else if (*p == '>')
  2827             {
  2828               ptrdiff_t abbrlen;
  2829               if (supported_abbr)
  2830                 {
  2831                   abbrlen = p - (str + 4);
  2832                   memmove (str + 3, str + 4, abbrlen);
  2833                 }
  2834               else
  2835                 {
  2836                   abbrlen = 3;
  2837                   memset (str + 3, 'Z', abbrlen);
  2838                 }
  2839               memmove (str + 3 + abbrlen, p + 1, strlen (p));
  2840               break;
  2841             }
  2842         }
  2843     }
  2844 
  2845   return _putenv (str);
  2846 }
  2847 
  2848 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
  2849 
  2850 /* The argv[] array holds ANSI-encoded strings, and so this function
  2851    works with ANS_encoded strings.  */
  2852 void
  2853 init_environment (char ** argv)
  2854 {
  2855   static const char * const tempdirs[] = {
  2856     "$TMPDIR", "$TEMP", "$TMP", "c:/"
  2857   };
  2858 
  2859   int i;
  2860 
  2861   const int imax = ARRAYELTS (tempdirs);
  2862 
  2863   /* Implementation note: This function explicitly works with ANSI
  2864      file names, not with UTF-8 encoded file names.  This is because
  2865      this function pushes variables into the Emacs's environment, and
  2866      the environment variables are always assumed to be in the
  2867      locale-specific encoding.  Do NOT call any functions that accept
  2868      UTF-8 file names from this function!  */
  2869 
  2870   /* Make sure they have a usable $TMPDIR.  Many Emacs functions use
  2871      temporary files and assume "/tmp" if $TMPDIR is unset, which
  2872      will break on DOS/Windows.  Refuse to work if we cannot find
  2873      a directory, not even "c:/", usable for that purpose.  */
  2874   for (i = 0; i < imax ; i++)
  2875     {
  2876       const char *tmp = tempdirs[i];
  2877 
  2878       if (*tmp == '$')
  2879         tmp = getenv (tmp + 1);
  2880       /* Note that `access' can lie to us if the directory resides on a
  2881          read-only filesystem, like CD-ROM or a write-protected floppy.
  2882          The only way to be really sure is to actually create a file and
  2883          see if it succeeds.  But I think that's too much to ask.  */
  2884 
  2885       /* MSVCRT's _access crashes with D_OK, so we use our replacement.  */
  2886       if (tmp && sys_access (tmp, D_OK) == 0)
  2887         {
  2888           char * var = alloca (strlen (tmp) + 8);
  2889           sprintf (var, "TMPDIR=%s", tmp);
  2890           _putenv (strdup (var));
  2891           break;
  2892         }
  2893     }
  2894   if (i >= imax)
  2895     cmd_error_internal
  2896       (Fcons (Qerror,
  2897               Fcons (build_string ("no usable temporary directories found!!"),
  2898                      Qnil)),
  2899        "While setting TMPDIR: ");
  2900 
  2901   /* Check for environment variables and use registry settings if they
  2902      don't exist.  Fallback on default values where applicable.  */
  2903   {
  2904     int i;
  2905     LPBYTE lpval;
  2906     DWORD dwType;
  2907     char locale_name[32];
  2908     char default_home[MAX_PATH];
  2909     int appdata = 0;
  2910 
  2911     static const struct env_entry
  2912     {
  2913       const char * name;
  2914       const char * def_value;
  2915     } dflt_envvars[] =
  2916     {
  2917       /* If the default value is NULL, we will use the value from the
  2918          outside environment or the Registry, but will not push the
  2919          variable into the Emacs environment if it is defined neither
  2920          in the Registry nor in the outside environment.  */
  2921       {"HOME", "C:/"},
  2922       {"PRELOAD_WINSOCK", NULL},
  2923       {"emacs_dir", "C:/emacs"},
  2924       {"EMACSLOADPATH", NULL},
  2925       {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
  2926       {"EMACSDATA", NULL},
  2927       {"EMACSPATH", NULL},
  2928       {"INFOPATH", NULL},
  2929       {"EMACSDOC", NULL},
  2930       {"TERM", "cmd"},
  2931       {"LANG", NULL},
  2932     };
  2933 
  2934 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
  2935 
  2936     /* We need to copy dflt_envvars[] and work on the copy because we
  2937        don't want the dumped Emacs to inherit the values of
  2938        environment variables we saw during dumping (which could be on
  2939        a different system).  The defaults above must be left intact.  */
  2940     struct env_entry env_vars[N_ENV_VARS];
  2941 
  2942     for (i = 0; i < N_ENV_VARS; i++)
  2943       env_vars[i] = dflt_envvars[i];
  2944 
  2945     /* For backwards compatibility, check if a .emacs file exists in C:/
  2946        If not, then we can try to default to the appdata directory under the
  2947        user's profile, which is more likely to be writable.   */
  2948     if (sys_access ("C:/.emacs", F_OK) != 0)
  2949       {
  2950         HRESULT profile_result;
  2951         /* Dynamically load ShGetFolderPath, as it won't exist on versions
  2952            of Windows 95 and NT4 that have not been updated to include
  2953            MSIE 5.  */
  2954         ShGetFolderPath_fn get_folder_path;
  2955         get_folder_path = (ShGetFolderPath_fn)
  2956           get_proc_addr (GetModuleHandle ("shell32.dll"),
  2957                                 "SHGetFolderPathA");
  2958 
  2959         if (get_folder_path != NULL)
  2960           {
  2961             profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
  2962                                               0, default_home);
  2963 
  2964             /* If we can't get the appdata dir, revert to old behavior.  */
  2965             if (profile_result == S_OK)
  2966               {
  2967                 env_vars[0].def_value = default_home;
  2968                 appdata = 1;
  2969               }
  2970           }
  2971       }
  2972 
  2973   /* Get default locale info and use it for LANG.  */
  2974   if (GetLocaleInfo (LOCALE_USER_DEFAULT,
  2975                      LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
  2976                      locale_name, sizeof (locale_name)))
  2977     {
  2978       /* Microsoft are migrating away of locale IDs, replacing them
  2979          with locale names, such as "en-US", and are therefore
  2980          deprecating the APIs which use LCID etc.  As part of that
  2981          deprecation, they don't bother inventing LCID and LANGID
  2982          codes for new locales and language/culture combinations;
  2983          instead, those get LCID of 0xC000 and LANGID of 0x2000, for
  2984          which the LCID/LANGID oriented APIs return "ZZZ" as the
  2985          "language name".  Such "language name" is useless for our
  2986          purposes.  So we instead use the default UI language, in the
  2987          hope of getting something usable.  */
  2988       if (strcmp (locale_name, "ZZZ") == 0)
  2989         {
  2990           LANGID lang_id = get_user_default_ui_language ();
  2991 
  2992           if (lang_id != 0)
  2993             {
  2994               /* Disregard the sorting order differences between cultures.  */
  2995               LCID def_lcid = MAKELCID (lang_id, SORT_DEFAULT);
  2996               char locale_name_def[32];
  2997 
  2998               if (GetLocaleInfo (def_lcid,
  2999                                  LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
  3000                                  locale_name_def, sizeof (locale_name_def)))
  3001                 strcpy (locale_name, locale_name_def);
  3002             }
  3003         }
  3004       for (i = 0; i < N_ENV_VARS; i++)
  3005         {
  3006           if (strcmp (env_vars[i].name, "LANG") == 0)
  3007             {
  3008               env_vars[i].def_value = locale_name;
  3009               break;
  3010             }
  3011         }
  3012     }
  3013 
  3014 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
  3015 
  3016     /* Treat emacs_dir specially: set it unconditionally based on our
  3017        location.  */
  3018     {
  3019       char *p;
  3020       char modname[MAX_PATH];
  3021 
  3022       if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
  3023         emacs_abort ();
  3024       if ((p = _mbsrchr (modname, '\\')) == NULL)
  3025         emacs_abort ();
  3026       *p = 0;
  3027 
  3028       if ((p = _mbsrchr (modname, '\\'))
  3029           /* From bin means installed Emacs, from src means uninstalled.  */
  3030           && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
  3031         {
  3032           char buf[SET_ENV_BUF_SIZE];
  3033           int within_build_tree = xstrcasecmp (p, "\\src") == 0;
  3034 
  3035           *p = 0;
  3036           for (p = modname; *p; p = CharNext (p))
  3037             if (*p == '\\') *p = '/';
  3038 
  3039           _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
  3040           _putenv (strdup (buf));
  3041           /* If we are running from the Posix-like build tree, define
  3042              SHELL to point to our own cmdproxy.  The loop below will
  3043              then disregard PATH_EXEC and the default value.  */
  3044           if (within_build_tree)
  3045             {
  3046               _snprintf (buf, sizeof (buf) - 1,
  3047                          "SHELL=%s/nt/cmdproxy.exe", modname);
  3048               _putenv (strdup (buf));
  3049             }
  3050         }
  3051     }
  3052 
  3053     for (i = 0; i < N_ENV_VARS; i++)
  3054       {
  3055         if (!getenv (env_vars[i].name))
  3056           {
  3057             int dont_free = 0;
  3058             char bufc[SET_ENV_BUF_SIZE];
  3059 
  3060             if ((lpval = w32_get_resource (REG_ROOT, env_vars[i].name, &dwType)) == NULL
  3061                 /* Also ignore empty environment variables.  */
  3062                 || *lpval == 0)
  3063               {
  3064                 xfree (lpval);
  3065                 dont_free = 1;
  3066                 if (strcmp (env_vars[i].name, "SHELL") == 0)
  3067                   {
  3068                     /* Look for cmdproxy.exe in every directory in
  3069                        PATH_EXEC.  FIXME: This does not find cmdproxy
  3070                        in nt/ when we run uninstalled.  */
  3071                     char fname[MAX_PATH];
  3072                     const char *pstart = PATH_EXEC, *pend;
  3073 
  3074                     do {
  3075                       pend = _mbschr (pstart, ';');
  3076                       if (!pend)
  3077                         pend = pstart + strlen (pstart);
  3078                       /* Be defensive against series of ;;; characters.  */
  3079                       if (pend > pstart)
  3080                         {
  3081                           strncpy (fname, pstart, pend - pstart);
  3082                           fname[pend - pstart] = '/';
  3083                           strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
  3084                           ExpandEnvironmentStrings ((LPSTR) fname, bufc,
  3085                                                     sizeof (bufc));
  3086                           if (sys_access (bufc, F_OK) == 0)
  3087                             {
  3088                               lpval = bufc;
  3089                               dwType = REG_SZ;
  3090                               break;
  3091                             }
  3092                         }
  3093                       if (*pend)
  3094                         pstart = pend + 1;
  3095                       else
  3096                         pstart = pend;
  3097                       if (!*pstart)
  3098                         {
  3099                           /* If not found in any directory, use the
  3100                              default as the last resort.  */
  3101                           lpval = (char *)env_vars[i].def_value;
  3102                           dwType = REG_EXPAND_SZ;
  3103                         }
  3104                     } while (*pstart);
  3105                   }
  3106                 else
  3107                   {
  3108                     lpval = (char *)env_vars[i].def_value;
  3109                     dwType = REG_EXPAND_SZ;
  3110                   }
  3111                 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
  3112                   Vdelayed_warnings_list
  3113                     = Fcons
  3114                     (list2 (intern ("initialization"), build_string
  3115                             ("Use of `C:\\.emacs' without defining `HOME'\n"
  3116                              "in the environment is deprecated, "
  3117                              "see `Windows HOME' in the Emacs manual.")),
  3118                      Vdelayed_warnings_list);
  3119               }
  3120 
  3121             if (lpval)
  3122               {
  3123                 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
  3124 
  3125                 if (dwType == REG_EXPAND_SZ)
  3126                   ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
  3127                 else if (dwType == REG_SZ)
  3128                   strcpy (buf1, (char *)lpval);
  3129                 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
  3130                   {
  3131                     _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
  3132                                buf1);
  3133                     _putenv (strdup (buf2));
  3134                   }
  3135 
  3136                 if (!dont_free)
  3137                   xfree (lpval);
  3138               }
  3139           }
  3140       }
  3141   }
  3142 
  3143   /* Rebuild system configuration to reflect invoking system.  */
  3144   Vsystem_configuration = build_string (EMACS_CONFIGURATION);
  3145 
  3146   /* Another special case: on NT, the PATH variable is actually named
  3147      "Path" although cmd.exe (perhaps NT itself) arranges for
  3148      environment variable lookup and setting to be case insensitive.
  3149      However, Emacs assumes a fully case sensitive environment, so we
  3150      need to change "Path" to "PATH" to match the expectations of
  3151      various elisp packages.  We do this by the sneaky method of
  3152      modifying the string in the C runtime environ entry.
  3153 
  3154      The same applies to COMSPEC.  */
  3155   {
  3156     char ** envp;
  3157     const char *path = "PATH=";
  3158     int path_len = strlen (path);
  3159     const char *comspec = "COMSPEC=";
  3160     int comspec_len = strlen (comspec);
  3161 
  3162     for (envp = environ; *envp; envp++)
  3163       if (_strnicmp (*envp, path, path_len) == 0)
  3164         memcpy (*envp, path, path_len);
  3165       else if (_strnicmp (*envp, comspec, comspec_len) == 0)
  3166         memcpy (*envp, comspec, comspec_len);
  3167 
  3168     /* Make the same modification to `process-environment' which has
  3169        already been initialized in set_initial_environment.  */
  3170     for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
  3171     {
  3172       Lisp_Object entry = XCAR (env);
  3173       if (_strnicmp (SDATA (entry), path, path_len) == 0)
  3174         for (int i = 0; i < path_len; i++)
  3175           SSET (entry, i, path[i]);
  3176       else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
  3177         for (int i = 0; i < comspec_len; i++)
  3178           SSET (entry, i, comspec[i]);
  3179     }
  3180   }
  3181 
  3182   /* Remember the initial working directory for getcwd.  */
  3183   w32_get_current_directory (startup_dir);
  3184 
  3185   {
  3186     static char modname[MAX_PATH];
  3187 
  3188     if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
  3189       emacs_abort ();
  3190     argv[0] = modname;
  3191   }
  3192 
  3193   /* Determine if there is a middle mouse button, to allow parse_button
  3194      to decide whether right mouse events should be mouse-2 or
  3195      mouse-3. */
  3196   w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
  3197 
  3198   init_user_info ();
  3199 }
  3200 
  3201 /* Called from expand-file-name when default-directory is not a string.  */
  3202 
  3203 char *
  3204 emacs_root_dir (void)
  3205 {
  3206   static char root_dir[MAX_UTF8_PATH];
  3207   const char *p;
  3208 
  3209   p = getenv ("emacs_dir");
  3210   if (p == NULL)
  3211     emacs_abort ();
  3212   filename_from_ansi (p, root_dir);
  3213   root_dir[parse_root (root_dir, NULL)] = '\0';
  3214   dostounix_filename (root_dir);
  3215   return root_dir;
  3216 }
  3217 
  3218 /* Emulate fdutimens.  */
  3219 
  3220 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
  3221    TIMESPEC[0] and TIMESPEC[1], respectively.
  3222    FD must be either negative -- in which case it is ignored --
  3223    or a file descriptor that is open on FILE.
  3224    If FD is nonnegative, then FILE can be NULL, which means
  3225    use just futimes instead of utimes.
  3226    If TIMESPEC is null, FAIL.
  3227    Return 0 on success, -1 (setting errno) on failure.  */
  3228 
  3229 int
  3230 fdutimens (int fd, char const *file, struct timespec const timespec[2])
  3231 {
  3232   if (!timespec)
  3233     {
  3234       errno = ENOSYS;
  3235       return -1;
  3236     }
  3237   if (fd < 0 && !file)
  3238     {
  3239       errno = EBADF;
  3240       return -1;
  3241     }
  3242   /* _futime's prototype defines 2nd arg as having the type 'struct
  3243      _utimbuf', while utime needs to accept 'struct utimbuf' for
  3244      compatibility with Posix.  So we need to use 2 different (but
  3245      equivalent) types to avoid compiler warnings, sigh.  */
  3246   if (fd >= 0)
  3247     {
  3248       struct _utimbuf _ut;
  3249 
  3250       _ut.actime = timespec[0].tv_sec;
  3251       _ut.modtime = timespec[1].tv_sec;
  3252       return _futime (fd, &_ut);
  3253     }
  3254   else
  3255     return utimensat (fd, file, timespec, 0);
  3256 }
  3257 
  3258 /* ------------------------------------------------------------------------- */
  3259 /* IO support and wrapper functions for the Windows API. */
  3260 /* ------------------------------------------------------------------------- */
  3261 
  3262 /* Place a wrapper around the MSVC version of ctime.  It returns NULL
  3263    on network directories, so we handle that case here.
  3264    (Ulrich Leodolter, 1/11/95).  */
  3265 char *
  3266 sys_ctime (const time_t *t)
  3267 {
  3268   char *str = (char *) ctime (t);
  3269   return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
  3270 }
  3271 
  3272 /* Emulate sleep...we could have done this with a define, but that
  3273    would necessitate including windows.h in the files that used it.
  3274    This is much easier.  */
  3275 void
  3276 sys_sleep (int seconds)
  3277 {
  3278   Sleep (seconds * 1000);
  3279 }
  3280 
  3281 /* Internal MSVC functions for low-level descriptor munging */
  3282 extern int __cdecl _set_osfhnd (int fd, long h);
  3283 extern int __cdecl _free_osfhnd (int fd);
  3284 
  3285 /* parallel array of private info on file handles */
  3286 filedesc fd_info [ MAXDESC ];
  3287 
  3288 typedef struct volume_info_data {
  3289   struct volume_info_data * next;
  3290 
  3291   /* time when info was obtained */
  3292   DWORD     timestamp;
  3293 
  3294   /* actual volume info */
  3295   char *    root_dir;
  3296   DWORD     serialnum;
  3297   DWORD     maxcomp;
  3298   DWORD     flags;
  3299   char *    name;
  3300   char *    type;
  3301 } volume_info_data;
  3302 
  3303 /* Global referenced by various functions.  */
  3304 static volume_info_data volume_info;
  3305 
  3306 /* Vector to indicate which drives are local and fixed (for which cached
  3307    data never expires).  */
  3308 static BOOL fixed_drives[26];
  3309 
  3310 /* Consider cached volume information to be stale if older than 10s,
  3311    at least for non-local drives.  Info for fixed drives is never stale.  */
  3312 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
  3313 #define VOLINFO_STILL_VALID( root_dir, info )           \
  3314   ( ( isalpha (root_dir[0]) &&                          \
  3315       fixed_drives[ DRIVE_INDEX (root_dir[0]) ] )       \
  3316     || GetTickCount () - info->timestamp < 10000 )
  3317 
  3318 /* Cache support functions.  */
  3319 
  3320 /* Simple linked list with linear search is sufficient.  */
  3321 static volume_info_data *volume_cache = NULL;
  3322 
  3323 static volume_info_data *
  3324 lookup_volume_info (char * root_dir)
  3325 {
  3326   volume_info_data * info;
  3327 
  3328   for (info = volume_cache; info; info = info->next)
  3329     if (xstrcasecmp (info->root_dir, root_dir) == 0)
  3330       break;
  3331   return info;
  3332 }
  3333 
  3334 static void
  3335 add_volume_info (char * root_dir, volume_info_data * info)
  3336 {
  3337   info->root_dir = xstrdup (root_dir);
  3338   unixtodos_filename (info->root_dir);
  3339   info->next = volume_cache;
  3340   volume_cache = info;
  3341 }
  3342 
  3343 
  3344 /* Wrapper for GetVolumeInformation, which uses caching to avoid
  3345    performance penalty (~2ms on 486 for local drives, 7.5ms for local
  3346    cdrom drive, ~5-10ms or more for remote drives on LAN).  */
  3347 static volume_info_data *
  3348 GetCachedVolumeInformation (char * root_dir)
  3349 {
  3350   volume_info_data * info;
  3351   char default_root[ MAX_UTF8_PATH ];
  3352   char  name[MAX_PATH+1];
  3353   char  type[MAX_PATH+1];
  3354 
  3355   /* NULL for root_dir means use root from current directory.  */
  3356   if (root_dir == NULL)
  3357     {
  3358       w32_get_current_directory (default_root);
  3359       parse_root (default_root, (const char **)&root_dir);
  3360       *root_dir = 0;
  3361       root_dir = default_root;
  3362     }
  3363 
  3364   /* Local fixed drives can be cached permanently.  Removable drives
  3365      cannot be cached permanently, since the volume name and serial
  3366      number (if nothing else) can change.  Remote drives should be
  3367      treated as if they are removable, since there is no sure way to
  3368      tell whether they are or not.  Also, the UNC association of drive
  3369      letters mapped to remote volumes can be changed at any time (even
  3370      by other processes) without notice.
  3371 
  3372      As a compromise, so we can benefit from caching info for remote
  3373      volumes, we use a simple expiry mechanism to invalidate cache
  3374      entries that are more than ten seconds old.  */
  3375 
  3376 #if 0
  3377   /* No point doing this, because WNetGetConnection is even slower than
  3378      GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
  3379      GetDriveType is about the only call of this type which does not
  3380      involve network access, and so is extremely quick).  */
  3381 
  3382   /* Map drive letter to UNC if remote. */
  3383   if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
  3384     {
  3385       char remote_name[ 256 ];
  3386       char drive[3] = { root_dir[0], ':' };
  3387 
  3388       if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
  3389           == NO_ERROR)
  3390         /* do something */ ;
  3391     }
  3392 #endif
  3393 
  3394   info = lookup_volume_info (root_dir);
  3395 
  3396   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
  3397     {
  3398       DWORD serialnum;
  3399       DWORD maxcomp;
  3400       DWORD flags;
  3401 
  3402       /* Info is not cached, or is stale. */
  3403       if (w32_unicode_filenames)
  3404         {
  3405           wchar_t root_w[MAX_PATH];
  3406           wchar_t  name_w[MAX_PATH+1];
  3407           wchar_t  type_w[MAX_PATH+1];
  3408 
  3409           filename_to_utf16 (root_dir, root_w);
  3410           if (!GetVolumeInformationW (root_w,
  3411                                      name_w, sizeof (name_w),
  3412                                      &serialnum,
  3413                                      &maxcomp,
  3414                                      &flags,
  3415                                      type_w, sizeof (type_w)))
  3416             return NULL;
  3417           /* Hmm... not really 100% correct, as these 2 are not file
  3418              names...  */
  3419           filename_from_utf16 (name_w, name);
  3420           filename_from_utf16 (type_w, type);
  3421         }
  3422       else
  3423         {
  3424           char root_a[MAX_PATH];
  3425           char  name_a[MAX_PATH+1];
  3426           char  type_a[MAX_PATH+1];
  3427 
  3428           filename_to_ansi (root_dir, root_a);
  3429           if (!GetVolumeInformationA (root_a,
  3430                                      name_a, sizeof (name_a),
  3431                                      &serialnum,
  3432                                      &maxcomp,
  3433                                      &flags,
  3434                                      type_a, sizeof (type_a)))
  3435             return NULL;
  3436           filename_from_ansi (name_a, name);
  3437           filename_from_ansi (type_a, type);
  3438         }
  3439 
  3440       /* Cache the volume information for future use, overwriting existing
  3441          entry if present.  */
  3442       if (info == NULL)
  3443         {
  3444           info = xmalloc (sizeof (volume_info_data));
  3445           add_volume_info (root_dir, info);
  3446         }
  3447       else
  3448         {
  3449           xfree (info->name);
  3450           xfree (info->type);
  3451         }
  3452 
  3453       info->name = xstrdup (name);
  3454       unixtodos_filename (info->name);
  3455       info->serialnum = serialnum;
  3456       info->maxcomp = maxcomp;
  3457       info->flags = flags;
  3458       info->type = xstrdup (type);
  3459       info->timestamp = GetTickCount ();
  3460     }
  3461 
  3462   return info;
  3463 }
  3464 
  3465 /* Get information on the volume where NAME is held; set path pointer to
  3466    start of pathname in NAME (past UNC header\volume header if present),
  3467    if pPath is non-NULL.
  3468 
  3469    Note: if NAME includes symlinks, the information is for the volume
  3470    of the symlink, not of its target.  That's because, even though
  3471    GetVolumeInformation returns information about the symlink target
  3472    of its argument, we only pass the root directory to
  3473    GetVolumeInformation, not the full NAME.  */
  3474 static int
  3475 get_volume_info (const char * name, const char ** pPath)
  3476 {
  3477   char temp[MAX_UTF8_PATH];
  3478   char *rootname = NULL;  /* default to current volume */
  3479   volume_info_data * info;
  3480   int root_len = parse_root (name, pPath);
  3481 
  3482   if (name == NULL)
  3483     return FALSE;
  3484 
  3485   /* Copy the root name of the volume, if given.  */
  3486   if (root_len)
  3487     {
  3488       strncpy (temp, name, root_len);
  3489       temp[root_len] = '\0';
  3490       unixtodos_filename (temp);
  3491       rootname = temp;
  3492     }
  3493 
  3494   info = GetCachedVolumeInformation (rootname);
  3495   if (info != NULL)
  3496     {
  3497       /* Set global referenced by other functions.  */
  3498       volume_info = *info;
  3499       return TRUE;
  3500     }
  3501   return FALSE;
  3502 }
  3503 
  3504 /* Determine if volume is FAT format (ie. only supports short 8.3
  3505    names); also set path pointer to start of pathname in name, if
  3506    pPath is non-NULL.  */
  3507 static int
  3508 is_fat_volume (const char * name, const char ** pPath)
  3509 {
  3510   if (get_volume_info (name, pPath))
  3511     return (volume_info.maxcomp == 12);
  3512   return FALSE;
  3513 }
  3514 
  3515 /* Convert all slashes in a filename to backslashes, and map filename
  3516    to a valid 8.3 name if necessary.  The result is a pointer to a
  3517    static buffer, so CAVEAT EMPTOR!  */
  3518 const char *
  3519 map_w32_filename (const char * name, const char ** pPath)
  3520 {
  3521   static char shortname[MAX_UTF8_PATH];
  3522   char * str = shortname;
  3523   char c;
  3524   char * path;
  3525   const char * save_name = name;
  3526 
  3527   if (strlen (name) >= sizeof (shortname))
  3528     {
  3529       /* Return a filename which will cause callers to fail.  */
  3530       strcpy (shortname, "?");
  3531       return shortname;
  3532     }
  3533 
  3534   if (!fatal_error_in_progress  /* disable fancy processing during crash */
  3535       && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
  3536     {
  3537       register int left = 8;    /* maximum number of chars in part */
  3538       register int extn = 0;    /* extension added? */
  3539       register int dots = 2;    /* maximum number of dots allowed */
  3540 
  3541       while (name < path)
  3542         *str++ = *name++;       /* skip past UNC header */
  3543 
  3544       while ((c = *name++))
  3545         {
  3546           switch ( c )
  3547             {
  3548             case ':':
  3549             case '\\':
  3550             case '/':
  3551               *str++ = (c == ':' ? ':' : '\\');
  3552               extn = 0;         /* reset extension flags */
  3553               dots = 2;         /* max 2 dots */
  3554               left = 8;         /* max length 8 for main part */
  3555               break;
  3556             case '.':
  3557               if ( dots )
  3558                 {
  3559                   /* Convert path components of the form .xxx to _xxx,
  3560                      but leave . and .. as they are.  This allows .emacs
  3561                      to be read as _emacs, for example.  */
  3562 
  3563                   if (! *name ||
  3564                       *name == '.' ||
  3565                       IS_DIRECTORY_SEP (*name))
  3566                     {
  3567                       *str++ = '.';
  3568                       dots--;
  3569                     }
  3570                   else
  3571                     {
  3572                       *str++ = '_';
  3573                       left--;
  3574                       dots = 0;
  3575                     }
  3576                 }
  3577               else if ( !extn )
  3578                 {
  3579                   *str++ = '.';
  3580                   extn = 1;             /* we've got an extension */
  3581                   left = 3;             /* 3 chars in extension */
  3582                 }
  3583               else
  3584                 {
  3585                   /* any embedded dots after the first are converted to _ */
  3586                   *str++ = '_';
  3587                 }
  3588               break;
  3589             case '~':
  3590             case '#':                   /* don't lose these, they're important */
  3591               if ( ! left )
  3592                 str[-1] = c;            /* replace last character of part */
  3593               /* FALLTHRU */
  3594               FALLTHROUGH;
  3595             default:
  3596               if ( left && 'A' <= c && c <= 'Z' )
  3597                 {
  3598                   *str++ = tolower (c); /* map to lower case (looks nicer) */
  3599                   left--;
  3600                   dots = 0;             /* started a path component */
  3601                 }
  3602               break;
  3603             }
  3604         }
  3605       *str = '\0';
  3606     }
  3607   else
  3608     {
  3609       strcpy (shortname, name);
  3610       unixtodos_filename (shortname);
  3611     }
  3612 
  3613   if (pPath)
  3614     *pPath = shortname + (path - save_name);
  3615 
  3616   return shortname;
  3617 }
  3618 
  3619 static int
  3620 is_exec (const char * name)
  3621 {
  3622   char * p = strrchr (name, '.');
  3623   return
  3624     (p != NULL
  3625      && (xstrcasecmp (p, ".exe") == 0 ||
  3626          xstrcasecmp (p, ".com") == 0 ||
  3627          xstrcasecmp (p, ".bat") == 0 ||
  3628          xstrcasecmp (p, ".cmd") == 0));
  3629 }
  3630 
  3631 /* Emulate the Unix directory procedures opendir, closedir, and
  3632    readdir.  We rename them to sys_* names because some versions of
  3633    MinGW startup code call opendir and readdir to glob wildcards, and
  3634    the code that calls them doesn't grok UTF-8 encoded file names we
  3635    produce in dirent->d_name[].  */
  3636 
  3637 struct dirent dir_static;       /* simulated directory contents */
  3638 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
  3639 static int    dir_is_fat;
  3640 static char   dir_pathname[MAX_UTF8_PATH];
  3641 static WIN32_FIND_DATAW dir_find_data_w;
  3642 static WIN32_FIND_DATAA dir_find_data_a;
  3643 #define DIR_FIND_DATA_W 1
  3644 #define DIR_FIND_DATA_A 2
  3645 static int    last_dir_find_data = -1;
  3646 
  3647 /* Support shares on a network resource as subdirectories of a read-only
  3648    root directory. */
  3649 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
  3650 static HANDLE open_unc_volume (const char *);
  3651 static void  *read_unc_volume (HANDLE, wchar_t *, char *, int);
  3652 static void   close_unc_volume (HANDLE);
  3653 
  3654 DIR *
  3655 sys_opendir (const char *filename)
  3656 {
  3657   DIR *dirp;
  3658 
  3659   /* Opening is done by FindFirstFile.  However, a read is inherent to
  3660      this operation, so we defer the open until read time.  */
  3661 
  3662   if (dir_find_handle != INVALID_HANDLE_VALUE)
  3663     return NULL;
  3664   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
  3665     return NULL;
  3666 
  3667   /* Note: We don't support traversal of UNC volumes via symlinks.
  3668      Doing so would mean punishing 99.99% of use cases by resolving
  3669      all the possible symlinks in FILENAME, recursively. */
  3670   if (is_unc_volume (filename))
  3671     {
  3672       wnet_enum_handle = open_unc_volume (filename);
  3673       if (wnet_enum_handle == INVALID_HANDLE_VALUE)
  3674         return NULL;
  3675     }
  3676 
  3677   if (!(dirp = (DIR *) malloc (sizeof (DIR))))
  3678     return NULL;
  3679 
  3680   dirp->dd_fd = 0;
  3681   dirp->dd_loc = 0;
  3682   dirp->dd_size = 0;
  3683 
  3684   strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
  3685   dir_pathname[MAX_UTF8_PATH - 1] = '\0';
  3686   /* Note: We don't support symlinks to file names on FAT volumes.
  3687      Doing so would mean punishing 99.99% of use cases by resolving
  3688      all the possible symlinks in FILENAME, recursively.  */
  3689   dir_is_fat = is_fat_volume (filename, NULL);
  3690 
  3691   return dirp;
  3692 }
  3693 
  3694 void
  3695 sys_closedir (DIR *dirp)
  3696 {
  3697   /* If we have a find-handle open, close it.  */
  3698   if (dir_find_handle != INVALID_HANDLE_VALUE)
  3699     {
  3700       FindClose (dir_find_handle);
  3701       dir_find_handle = INVALID_HANDLE_VALUE;
  3702     }
  3703   else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
  3704     {
  3705       close_unc_volume (wnet_enum_handle);
  3706       wnet_enum_handle = INVALID_HANDLE_VALUE;
  3707     }
  3708   xfree ((char *) dirp);
  3709 }
  3710 
  3711 struct dirent *
  3712 sys_readdir (DIR *dirp)
  3713 {
  3714   int downcase = !NILP (Vw32_downcase_file_names);
  3715 
  3716   if (wnet_enum_handle != INVALID_HANDLE_VALUE)
  3717     {
  3718       if (!read_unc_volume (wnet_enum_handle,
  3719                             dir_find_data_w.cFileName,
  3720                             dir_find_data_a.cFileName,
  3721                             MAX_PATH))
  3722         return NULL;
  3723     }
  3724   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
  3725   else if (dir_find_handle == INVALID_HANDLE_VALUE)
  3726     {
  3727       char filename[MAX_UTF8_PATH];
  3728       int ln;
  3729       bool last_slash = true;
  3730 
  3731       /* Note: We don't need to worry about dir_pathname being longer
  3732          than MAX_UTF8_PATH, as sys_opendir already took care of that
  3733          when it called map_w32_filename: that function will put a "?"
  3734          in its return value in that case, thus failing all the calls
  3735          below.  */
  3736       strcpy (filename, dir_pathname);
  3737       ln = strlen (filename);
  3738       if (!IS_DIRECTORY_SEP (filename[ln - 1]))
  3739         last_slash = false;
  3740 
  3741       /* Note: No need to resolve symlinks in FILENAME, because
  3742          FindFirst opens the directory that is the target of a
  3743          symlink.  */
  3744       if (w32_unicode_filenames)
  3745         {
  3746           wchar_t fnw[MAX_PATH + 2];
  3747 
  3748           filename_to_utf16 (filename, fnw);
  3749           if (!last_slash)
  3750             wcscat (fnw, L"\\");
  3751           wcscat (fnw, L"*");
  3752           dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
  3753         }
  3754       else
  3755         {
  3756           char fna[MAX_PATH + 2];
  3757 
  3758           filename_to_ansi (filename, fna);
  3759           if (!last_slash)
  3760             strcat (fna, "\\");
  3761           strcat (fna, "*");
  3762           /* If FILENAME is not representable by the current ANSI
  3763              codepage, we don't want FindFirstFileA to interpret the
  3764              '?' characters as a wildcard.  */
  3765           if (_mbspbrk (fna, "?"))
  3766             dir_find_handle = INVALID_HANDLE_VALUE;
  3767           else
  3768             dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
  3769         }
  3770 
  3771       if (dir_find_handle == INVALID_HANDLE_VALUE)
  3772         {
  3773           /* Any changes in the value of errno here should be in sync
  3774              with what directory_files_internal does when it calls
  3775              readdir.  */
  3776           switch (GetLastError ())
  3777             {
  3778               /* Windows uses this value when FindFirstFile finds no
  3779                  files that match the wildcard.  This is not supposed
  3780                  to happen, since our wildcard is "*", but just in
  3781                  case, if there's some weird empty directory with not
  3782                  even "." and ".." entries...  */
  3783             case ERROR_FILE_NOT_FOUND:
  3784               errno = 0;
  3785               /* FALLTHRU */
  3786             default:
  3787               break;
  3788             case ERROR_ACCESS_DENIED:
  3789             case ERROR_NETWORK_ACCESS_DENIED:
  3790               errno = EACCES;
  3791               break;
  3792             case ERROR_PATH_NOT_FOUND:
  3793             case ERROR_INVALID_DRIVE:
  3794             case ERROR_NOT_READY:
  3795             case ERROR_BAD_NETPATH:
  3796             case ERROR_BAD_NET_NAME:
  3797               errno = ENOENT;
  3798               break;
  3799             }
  3800           return NULL;
  3801         }
  3802     }
  3803   else if (w32_unicode_filenames)
  3804     {
  3805       if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
  3806         {
  3807           errno = 0;
  3808           return NULL;
  3809         }
  3810     }
  3811   else
  3812     {
  3813       if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
  3814         {
  3815           errno = 0;
  3816           return NULL;
  3817         }
  3818     }
  3819 
  3820   /* Emacs never uses this value, so don't bother making it match
  3821      value returned by stat().  */
  3822   dir_static.d_ino = 1;
  3823 
  3824   if (w32_unicode_filenames)
  3825     {
  3826       if (downcase || dir_is_fat)
  3827         {
  3828           wchar_t tem[MAX_PATH];
  3829 
  3830           wcscpy (tem, dir_find_data_w.cFileName);
  3831           CharLowerW (tem);
  3832           filename_from_utf16 (tem, dir_static.d_name);
  3833         }
  3834       else
  3835         filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
  3836       last_dir_find_data = DIR_FIND_DATA_W;
  3837     }
  3838   else
  3839     {
  3840       char tem[MAX_PATH];
  3841 
  3842       /* If the file name in cFileName[] includes `?' characters, it
  3843          means the original file name used characters that cannot be
  3844          represented by the current ANSI codepage.  To avoid total
  3845          lossage, retrieve the short 8+3 alias of the long file
  3846          name.  */
  3847       if (_mbspbrk (dir_find_data_a.cFileName, "?"))
  3848         {
  3849           strcpy (tem, dir_find_data_a.cAlternateFileName);
  3850           /* 8+3 aliases are returned in all caps, which could break
  3851              various alists that look at filenames' extensions.  */
  3852           downcase = 1;
  3853         }
  3854       else if (downcase || dir_is_fat)
  3855         strcpy (tem, dir_find_data_a.cFileName);
  3856       else
  3857         filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
  3858       if (downcase || dir_is_fat)
  3859         {
  3860           _mbslwr (tem);
  3861           filename_from_ansi (tem, dir_static.d_name);
  3862         }
  3863       last_dir_find_data = DIR_FIND_DATA_A;
  3864     }
  3865 
  3866   dir_static.d_namlen = strlen (dir_static.d_name);
  3867   dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
  3868     dir_static.d_namlen - dir_static.d_namlen % 4;
  3869 
  3870   return &dir_static;
  3871 }
  3872 
  3873 static HANDLE
  3874 open_unc_volume (const char *path)
  3875 {
  3876   const char *fn = map_w32_filename (path, NULL);
  3877   DWORD result;
  3878   HANDLE henum;
  3879 
  3880   if (w32_unicode_filenames)
  3881     {
  3882       NETRESOURCEW nrw;
  3883       wchar_t fnw[MAX_PATH];
  3884 
  3885       nrw.dwScope = RESOURCE_GLOBALNET;
  3886       nrw.dwType = RESOURCETYPE_DISK;
  3887       nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  3888       nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
  3889       nrw.lpLocalName = NULL;
  3890       filename_to_utf16 (fn, fnw);
  3891       nrw.lpRemoteName = fnw;
  3892       nrw.lpComment = NULL;
  3893       nrw.lpProvider = NULL;
  3894 
  3895       result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
  3896                               RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
  3897     }
  3898   else
  3899     {
  3900       NETRESOURCEA nra;
  3901       char fna[MAX_PATH];
  3902 
  3903       nra.dwScope = RESOURCE_GLOBALNET;
  3904       nra.dwType = RESOURCETYPE_DISK;
  3905       nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  3906       nra.dwUsage = RESOURCEUSAGE_CONTAINER;
  3907       nra.lpLocalName = NULL;
  3908       filename_to_ansi (fn, fna);
  3909       nra.lpRemoteName = fna;
  3910       nra.lpComment = NULL;
  3911       nra.lpProvider = NULL;
  3912 
  3913       result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
  3914                               RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
  3915     }
  3916   if (result == NO_ERROR)
  3917     return henum;
  3918   else
  3919     {
  3920       /* Make sure directory_files_internal reports a sensible error.  */
  3921       errno = ENOENT;
  3922       return INVALID_HANDLE_VALUE;
  3923     }
  3924 }
  3925 
  3926 static void *
  3927 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
  3928 {
  3929   DWORD count;
  3930   int result;
  3931   char *buffer;
  3932   DWORD bufsize = 512;
  3933   void *retval;
  3934 
  3935   count = 1;
  3936   if (w32_unicode_filenames)
  3937     {
  3938       wchar_t *ptrw;
  3939 
  3940       bufsize *= 2;
  3941       buffer = alloca (bufsize);
  3942       result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
  3943       if (result != NO_ERROR)
  3944         return NULL;
  3945       /* WNetEnumResource returns \\resource\share...skip forward to "share". */
  3946       ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
  3947       ptrw += 2;
  3948       while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
  3949       ptrw++;
  3950       wcsncpy (fname_w, ptrw, size);
  3951       retval = fname_w;
  3952     }
  3953   else
  3954     {
  3955       int dbcs_p = max_filename_mbslen () > 1;
  3956       char *ptra;
  3957 
  3958       buffer = alloca (bufsize);
  3959       result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
  3960       if (result != NO_ERROR)
  3961         return NULL;
  3962       ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
  3963       ptra += 2;
  3964       if (!dbcs_p)
  3965         while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
  3966       else
  3967         {
  3968           while (*ptra && !IS_DIRECTORY_SEP (*ptra))
  3969             ptra = CharNextExA (file_name_codepage, ptra, 0);
  3970         }
  3971       ptra++;
  3972       strncpy (fname_a, ptra, size);
  3973       retval = fname_a;
  3974     }
  3975 
  3976   return retval;
  3977 }
  3978 
  3979 static void
  3980 close_unc_volume (HANDLE henum)
  3981 {
  3982   if (henum != INVALID_HANDLE_VALUE)
  3983     WNetCloseEnum (henum);
  3984 }
  3985 
  3986 static DWORD
  3987 unc_volume_file_attributes (const char *path)
  3988 {
  3989   HANDLE henum;
  3990   DWORD attrs;
  3991 
  3992   henum = open_unc_volume (path);
  3993   if (henum == INVALID_HANDLE_VALUE)
  3994     return -1;
  3995 
  3996   attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
  3997 
  3998   close_unc_volume (henum);
  3999 
  4000   return attrs;
  4001 }
  4002 
  4003 /* Ensure a network connection is authenticated.  */
  4004 static void
  4005 logon_network_drive (const char *path)
  4006 {
  4007   char share[MAX_UTF8_PATH];
  4008   int n_slashes;
  4009   char drive[4];
  4010   UINT drvtype;
  4011   char *p;
  4012   DWORD val;
  4013 
  4014   if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
  4015     drvtype = DRIVE_REMOTE;
  4016   else if (path[0] == '\0' || path[1] != ':')
  4017     drvtype = GetDriveType (NULL);
  4018   else
  4019     {
  4020       drive[0] = path[0];
  4021       drive[1] = ':';
  4022       drive[2] = '\\';
  4023       drive[3] = '\0';
  4024       drvtype = GetDriveType (drive);
  4025     }
  4026 
  4027   /* Only logon to networked drives.  */
  4028   if (drvtype != DRIVE_REMOTE)
  4029     return;
  4030 
  4031   n_slashes = 2;
  4032   strncpy (share, path, MAX_UTF8_PATH - 1);
  4033   /* Truncate to just server and share name.  */
  4034   for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
  4035     {
  4036       if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
  4037         {
  4038           *p = '\0';
  4039           break;
  4040         }
  4041     }
  4042 
  4043   if (w32_unicode_filenames)
  4044     {
  4045       NETRESOURCEW resourcew;
  4046       wchar_t share_w[MAX_PATH];
  4047 
  4048       resourcew.dwScope = RESOURCE_GLOBALNET;
  4049       resourcew.dwType = RESOURCETYPE_DISK;
  4050       resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4051       resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
  4052       resourcew.lpLocalName = NULL;
  4053       filename_to_utf16 (share, share_w);
  4054       resourcew.lpRemoteName = share_w;
  4055       resourcew.lpProvider = NULL;
  4056 
  4057       val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
  4058     }
  4059   else
  4060     {
  4061       NETRESOURCEA resourcea;
  4062       char share_a[MAX_PATH];
  4063 
  4064       resourcea.dwScope = RESOURCE_GLOBALNET;
  4065       resourcea.dwType = RESOURCETYPE_DISK;
  4066       resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4067       resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
  4068       resourcea.lpLocalName = NULL;
  4069       filename_to_ansi (share, share_a);
  4070       resourcea.lpRemoteName = share_a;
  4071       resourcea.lpProvider = NULL;
  4072 
  4073       val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
  4074     }
  4075 
  4076   switch (val)
  4077     {
  4078     case NO_ERROR:
  4079     case ERROR_ALREADY_ASSIGNED:
  4080       break;
  4081     case ERROR_ACCESS_DENIED:
  4082     case ERROR_LOGON_FAILURE:
  4083       errno = EACCES;
  4084       break;
  4085     case ERROR_BUSY:
  4086       errno = EAGAIN;
  4087       break;
  4088     case ERROR_BAD_NET_NAME:
  4089     case ERROR_NO_NET_OR_BAD_PATH:
  4090     case ERROR_NO_NETWORK:
  4091     case ERROR_CANCELLED:
  4092     default:
  4093       errno = ENOENT;
  4094       break;
  4095     }
  4096 }
  4097 
  4098 /* Emulate faccessat(2).  */
  4099 int
  4100 faccessat (int dirfd, const char * path, int mode, int flags)
  4101 {
  4102   DWORD attributes;
  4103   char fullname[MAX_UTF8_PATH];
  4104 
  4105   /* Rely on a hack: an open directory is modeled as file descriptor 0,
  4106      and its actual file name is stored in dir_pathname by opendir.
  4107      This is good enough for the current usage in Emacs, but is fragile.  */
  4108   if (dirfd != AT_FDCWD
  4109       && !(IS_DIRECTORY_SEP (path[0])
  4110            || IS_DEVICE_SEP (path[1])))
  4111     {
  4112       char lastc = dir_pathname[strlen (dir_pathname) - 1];
  4113 
  4114       if (_snprintf (fullname, sizeof fullname, "%s%s%s",
  4115                      dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
  4116           < 0)
  4117         {
  4118           errno = ENAMETOOLONG;
  4119           return -1;
  4120         }
  4121       path = fullname;
  4122     }
  4123 
  4124   /* When dired.c calls us with F_OK and a trailing slash, it actually
  4125      wants to know whether PATH is a directory.  */
  4126   if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && mode == F_OK)
  4127     mode |= D_OK;
  4128 
  4129   /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
  4130      newer versions blow up when passed D_OK.  */
  4131   path = map_w32_filename (path, NULL);
  4132   /* If the last element of PATH is a symlink, we need to resolve it
  4133      to get the attributes of its target file.  Note: any symlinks in
  4134      PATH elements other than the last one are transparently resolved
  4135      by GetFileAttributes below.  */
  4136   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
  4137       && (flags & AT_SYMLINK_NOFOLLOW) == 0)
  4138     path = chase_symlinks (path);
  4139 
  4140   if (w32_unicode_filenames)
  4141     {
  4142       wchar_t path_w[MAX_PATH];
  4143 
  4144       filename_to_utf16 (path, path_w);
  4145       attributes = GetFileAttributesW (path_w);
  4146     }
  4147   else
  4148     {
  4149       char path_a[MAX_PATH];
  4150 
  4151       filename_to_ansi (path, path_a);
  4152       attributes = GetFileAttributesA (path_a);
  4153     }
  4154 
  4155   if (attributes == -1)
  4156     {
  4157       DWORD w32err = GetLastError ();
  4158 
  4159       switch (w32err)
  4160         {
  4161         case ERROR_INVALID_NAME:
  4162         case ERROR_BAD_PATHNAME:
  4163           if (is_unc_volume (path))
  4164             {
  4165               attributes = unc_volume_file_attributes (path);
  4166               if (attributes == -1)
  4167                 {
  4168                   errno = EACCES;
  4169                   return -1;
  4170                 }
  4171               goto check_attrs;
  4172             }
  4173           /* FALLTHROUGH */
  4174           FALLTHROUGH;
  4175         case ERROR_FILE_NOT_FOUND:
  4176         case ERROR_PATH_NOT_FOUND:
  4177         case ERROR_INVALID_DRIVE:
  4178         case ERROR_NOT_READY:
  4179         case ERROR_BAD_NETPATH:
  4180         case ERROR_BAD_NET_NAME:
  4181           errno = ENOENT;
  4182           break;
  4183         default:
  4184           errno = EACCES;
  4185           break;
  4186         }
  4187       return -1;
  4188     }
  4189 
  4190  check_attrs:
  4191   if ((mode & X_OK) != 0
  4192       && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
  4193     {
  4194       errno = EACCES;
  4195       return -1;
  4196     }
  4197   if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
  4198     {
  4199       errno = EACCES;
  4200       return -1;
  4201     }
  4202   if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  4203     {
  4204       errno = EACCES;
  4205       return -1;
  4206     }
  4207   return 0;
  4208 }
  4209 
  4210 /* A special test for DIRNAME being a directory accessible by the
  4211    current user.  This is needed because the security permissions in
  4212    directory's ACLs are not visible in the Posix-style mode bits
  4213    returned by 'stat' and in attributes returned by GetFileAttributes.
  4214    So a directory would seem like it's readable by the current user,
  4215    but will in fact error out with EACCES when they actually try.  */
  4216 int
  4217 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
  4218 {
  4219   char pattern[MAX_UTF8_PATH];
  4220   bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
  4221   HANDLE dh;
  4222 
  4223   /* Network volumes need a different reading method.  */
  4224   if (is_unc_volume (dirname))
  4225     {
  4226       void *read_result = NULL;
  4227       wchar_t fnw[MAX_PATH];
  4228       char fna[MAX_PATH];
  4229 
  4230       dh = open_unc_volume (dirname);
  4231       if (dh != INVALID_HANDLE_VALUE)
  4232         {
  4233           read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
  4234           close_unc_volume (dh);
  4235         }
  4236       /* Treat empty volumes as accessible.  */
  4237       return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
  4238     }
  4239 
  4240   /* Note: map_w32_filename makes sure DIRNAME is not longer than
  4241      MAX_UTF8_PATH.  */
  4242   strcpy (pattern, map_w32_filename (dirname, NULL));
  4243 
  4244   /* Note: No need to resolve symlinks in FILENAME, because FindFirst
  4245      opens the directory that is the target of a symlink.  */
  4246   if (w32_unicode_filenames)
  4247     {
  4248       wchar_t pat_w[MAX_PATH + 2];
  4249       WIN32_FIND_DATAW dfd_w;
  4250 
  4251       filename_to_utf16 (pattern, pat_w);
  4252       if (!last_slash)
  4253         wcscat (pat_w, L"\\");
  4254       wcscat (pat_w, L"*");
  4255       dh = FindFirstFileW (pat_w, &dfd_w);
  4256     }
  4257   else
  4258     {
  4259       char pat_a[MAX_PATH + 2];
  4260       WIN32_FIND_DATAA dfd_a;
  4261 
  4262       filename_to_ansi (pattern, pat_a);
  4263       if (!last_slash)
  4264         strcpy (pat_a, "\\");
  4265       strcat (pat_a, "*");
  4266       /* In case DIRNAME cannot be expressed in characters from the
  4267          current ANSI codepage.  */
  4268       if (_mbspbrk (pat_a, "?"))
  4269         {
  4270           errno = ENOENT;
  4271           return 0;
  4272         }
  4273       dh = FindFirstFileA (pat_a, &dfd_a);
  4274     }
  4275 
  4276   if (dh == INVALID_HANDLE_VALUE)
  4277     {
  4278       DWORD w32err = GetLastError ();
  4279 
  4280       switch (w32err)
  4281         {
  4282         case ERROR_INVALID_NAME:
  4283         case ERROR_BAD_PATHNAME:
  4284         case ERROR_FILE_NOT_FOUND:
  4285         case ERROR_PATH_NOT_FOUND:
  4286         case ERROR_NO_MORE_FILES:
  4287         case ERROR_BAD_NETPATH:
  4288           errno = ENOENT;
  4289           break;
  4290         case ERROR_NOT_READY:
  4291           errno = ENODEV;
  4292           break;
  4293         default:
  4294           errno = EACCES;
  4295           break;
  4296         }
  4297     return 0;
  4298     }
  4299   FindClose (dh);
  4300   return 1;
  4301 }
  4302 
  4303 /* A version of 'access' to be used locally with file names in
  4304    locale-specific encoding.  Does not resolve symlinks and does not
  4305    support file names on FAT12 and FAT16 volumes, but that's OK, since
  4306    we only invoke this function for files inside the Emacs source or
  4307    installation tree, on directories (so any symlinks should have the
  4308    directory bit set), and on short file names such as "C:/.emacs".  */
  4309 static int
  4310 sys_access (const char *fname, int mode)
  4311 {
  4312   char fname_copy[MAX_PATH], *p;
  4313   DWORD attributes;
  4314 
  4315   strcpy (fname_copy, fname);
  4316   /* Do the equivalent of unixtodos_filename.  */
  4317   for (p = fname_copy; *p; p = CharNext (p))
  4318     if (*p == '/')
  4319       *p = '\\';
  4320 
  4321   if ((attributes = GetFileAttributesA (fname_copy)) == -1)
  4322     {
  4323       DWORD w32err = GetLastError ();
  4324 
  4325       switch (w32err)
  4326         {
  4327         case ERROR_INVALID_NAME:
  4328         case ERROR_BAD_PATHNAME:
  4329         case ERROR_FILE_NOT_FOUND:
  4330         case ERROR_BAD_NETPATH:
  4331           errno = ENOENT;
  4332           break;
  4333         default:
  4334           errno = EACCES;
  4335           break;
  4336         }
  4337       return -1;
  4338     }
  4339   if ((mode & X_OK) != 0
  4340       && !(is_exec (fname_copy)
  4341            || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
  4342     {
  4343       errno = EACCES;
  4344       return -1;
  4345     }
  4346   if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
  4347     {
  4348       errno = EACCES;
  4349       return -1;
  4350     }
  4351   if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  4352     {
  4353       errno = EACCES;
  4354       return -1;
  4355     }
  4356   return 0;
  4357 }
  4358 
  4359 /* Shadow some MSVC runtime functions to map requests for long filenames
  4360    to reasonable short names if necessary.  This was originally added to
  4361    permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
  4362    long file names.  */
  4363 
  4364 int
  4365 sys_chdir (const char * path)
  4366 {
  4367   path = map_w32_filename (path, NULL);
  4368   if (w32_unicode_filenames)
  4369     {
  4370       wchar_t newdir_w[MAX_PATH];
  4371 
  4372       if (filename_to_utf16 (path, newdir_w) == 0)
  4373         return _wchdir (newdir_w);
  4374       return -1;
  4375     }
  4376   else
  4377     {
  4378       char newdir_a[MAX_PATH];
  4379 
  4380       if (filename_to_ansi (path, newdir_a) == 0)
  4381         return _chdir (newdir_a);
  4382       return -1;
  4383     }
  4384 }
  4385 
  4386 static int
  4387 chmod_worker (const char * path, int mode)
  4388 {
  4389   if (w32_unicode_filenames)
  4390     {
  4391       wchar_t path_w[MAX_PATH];
  4392 
  4393       filename_to_utf16 (path, path_w);
  4394       return _wchmod (path_w, mode);
  4395     }
  4396   else
  4397     {
  4398       char path_a[MAX_PATH];
  4399 
  4400       filename_to_ansi (path, path_a);
  4401       return _chmod (path_a, mode);
  4402     }
  4403 }
  4404 
  4405 int
  4406 sys_chmod (const char * path, int mode)
  4407 {
  4408   path = chase_symlinks (map_w32_filename (path, NULL));
  4409   return chmod_worker (path, mode);
  4410 }
  4411 
  4412 int
  4413 lchmod (const char * path, mode_t mode)
  4414 {
  4415   path = map_w32_filename (path, NULL);
  4416   return chmod_worker (path, mode);
  4417 }
  4418 
  4419 int
  4420 sys_creat (const char * path, int mode)
  4421 {
  4422   path = map_w32_filename (path, NULL);
  4423   if (w32_unicode_filenames)
  4424     {
  4425       wchar_t path_w[MAX_PATH];
  4426 
  4427       filename_to_utf16 (path, path_w);
  4428       return _wcreat (path_w, mode);
  4429     }
  4430   else
  4431     {
  4432       char path_a[MAX_PATH];
  4433 
  4434       filename_to_ansi (path, path_a);
  4435       return _creat (path_a, mode);
  4436     }
  4437 }
  4438 
  4439 FILE *
  4440 sys_fopen (const char * path, const char * mode)
  4441 {
  4442   int fd;
  4443   int oflag;
  4444   const char * mode_save = mode;
  4445 
  4446   /* Force all file handles to be non-inheritable.  This is necessary to
  4447      ensure child processes don't unwittingly inherit handles that might
  4448      prevent future file access. */
  4449 
  4450   if (mode[0] == 'r')
  4451     oflag = O_RDONLY;
  4452   else if (mode[0] == 'w' || mode[0] == 'a')
  4453     oflag = O_WRONLY | O_CREAT | O_TRUNC;
  4454   else
  4455     return NULL;
  4456 
  4457   /* Only do simplistic option parsing. */
  4458   while (*++mode)
  4459     if (mode[0] == '+')
  4460       {
  4461         oflag &= ~(O_RDONLY | O_WRONLY);
  4462         oflag |= O_RDWR;
  4463       }
  4464     else if (mode[0] == 'b')
  4465       {
  4466         oflag &= ~O_TEXT;
  4467         oflag |= O_BINARY;
  4468       }
  4469     else if (mode[0] == 't')
  4470       {
  4471         oflag &= ~O_BINARY;
  4472         oflag |= O_TEXT;
  4473       }
  4474     else break;
  4475 
  4476   path = map_w32_filename (path, NULL);
  4477   if (w32_unicode_filenames)
  4478     {
  4479       wchar_t path_w[MAX_PATH];
  4480 
  4481       filename_to_utf16 (path, path_w);
  4482       fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
  4483     }
  4484   else
  4485     {
  4486       char path_a[MAX_PATH];
  4487 
  4488       filename_to_ansi (path, path_a);
  4489       fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
  4490     }
  4491   if (fd < 0)
  4492     return NULL;
  4493 
  4494   return _fdopen (fd, mode_save);
  4495 }
  4496 
  4497 /* This only works on NTFS volumes, but is useful to have.  */
  4498 int
  4499 sys_link (const char * old, const char * new)
  4500 {
  4501   HANDLE fileh;
  4502   int   result = -1;
  4503   char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
  4504   wchar_t oldname_w[MAX_PATH];
  4505   char oldname_a[MAX_PATH];
  4506 
  4507   if (old == NULL || new == NULL)
  4508     {
  4509       errno = ENOENT;
  4510       return -1;
  4511     }
  4512 
  4513   strcpy (oldname, map_w32_filename (old, NULL));
  4514   strcpy (newname, map_w32_filename (new, NULL));
  4515 
  4516   if (w32_unicode_filenames)
  4517     {
  4518       filename_to_utf16 (oldname, oldname_w);
  4519       fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
  4520                            FILE_FLAG_BACKUP_SEMANTICS, NULL);
  4521     }
  4522   else
  4523     {
  4524       filename_to_ansi (oldname, oldname_a);
  4525       fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
  4526                            FILE_FLAG_BACKUP_SEMANTICS, NULL);
  4527     }
  4528   if (fileh != INVALID_HANDLE_VALUE)
  4529     {
  4530       int wlen;
  4531 
  4532       /* Confusingly, the "alternate" stream name field does not apply
  4533          when restoring a hard link, and instead contains the actual
  4534          stream data for the link (ie. the name of the link to create).
  4535          The WIN32_STREAM_ID structure before the cStreamName field is
  4536          the stream header, which is then immediately followed by the
  4537          stream data.  */
  4538 
  4539       struct {
  4540         WIN32_STREAM_ID wid;
  4541         WCHAR wbuffer[MAX_PATH];        /* extra space for link name */
  4542       } data;
  4543 
  4544       /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
  4545          indicates that flag is unsupported for CP_UTF8, and OTOH says
  4546          it is the default anyway.  */
  4547       wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
  4548                                    data.wid.cStreamName, MAX_PATH);
  4549       if (wlen > 0)
  4550         {
  4551           LPVOID context = NULL;
  4552           DWORD wbytes = 0;
  4553 
  4554           data.wid.dwStreamId = BACKUP_LINK;
  4555           data.wid.dwStreamAttributes = 0;
  4556           data.wid.Size.LowPart = wlen * sizeof (WCHAR);
  4557           data.wid.Size.HighPart = 0;
  4558           data.wid.dwStreamNameSize = 0;
  4559 
  4560           if (BackupWrite (fileh, (LPBYTE)&data,
  4561                            offsetof (WIN32_STREAM_ID, cStreamName)
  4562                            + data.wid.Size.LowPart,
  4563                            &wbytes, FALSE, FALSE, &context)
  4564               && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
  4565             {
  4566               /* succeeded */
  4567               result = 0;
  4568             }
  4569           else
  4570             {
  4571               DWORD err = GetLastError ();
  4572               DWORD attributes;
  4573 
  4574               switch (err)
  4575                 {
  4576                 case ERROR_ACCESS_DENIED:
  4577                   /* This is what happens when OLDNAME is a directory,
  4578                      since Windows doesn't support hard links to
  4579                      directories.  Posix says to set errno to EPERM in
  4580                      that case.  */
  4581                   if (w32_unicode_filenames)
  4582                     attributes = GetFileAttributesW (oldname_w);
  4583                   else
  4584                     attributes = GetFileAttributesA (oldname_a);
  4585                   if (attributes != -1
  4586                       && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4587                     errno = EPERM;
  4588                   else if (attributes == -1
  4589                            && is_unc_volume (oldname)
  4590                            && unc_volume_file_attributes (oldname) != -1)
  4591                     errno = EPERM;
  4592                   else
  4593                     errno = EACCES;
  4594                   break;
  4595                 case ERROR_TOO_MANY_LINKS:
  4596                   errno = EMLINK;
  4597                   break;
  4598                 case ERROR_NOT_SAME_DEVICE:
  4599                   errno = EXDEV;
  4600                   break;
  4601                 default:
  4602                   errno = EINVAL;
  4603                   break;
  4604                 }
  4605             }
  4606         }
  4607 
  4608       CloseHandle (fileh);
  4609     }
  4610   else
  4611     errno = ENOENT;
  4612 
  4613   return result;
  4614 }
  4615 
  4616 int
  4617 sys_mkdir (const char * path, mode_t mode)
  4618 {
  4619   path = map_w32_filename (path, NULL);
  4620 
  4621   if (w32_unicode_filenames)
  4622     {
  4623       wchar_t path_w[MAX_PATH];
  4624 
  4625       filename_to_utf16 (path, path_w);
  4626       return _wmkdir (path_w);
  4627     }
  4628   else
  4629     {
  4630       char path_a[MAX_PATH];
  4631 
  4632       filename_to_ansi (path, path_a);
  4633       return _mkdir (path_a);
  4634     }
  4635 }
  4636 
  4637 int
  4638 sys_open (const char * path, int oflag, int mode)
  4639 {
  4640   const char* mpath = map_w32_filename (path, NULL);
  4641   int res = -1;
  4642 
  4643   if (w32_unicode_filenames)
  4644     {
  4645       wchar_t mpath_w[MAX_PATH];
  4646 
  4647       filename_to_utf16 (mpath, mpath_w);
  4648       /* If possible, try to open file without _O_CREAT, to be able to
  4649          write to existing hidden and system files.  Force all file
  4650          handles to be non-inheritable. */
  4651       if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
  4652         res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
  4653       if (res < 0)
  4654         res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
  4655     }
  4656   else
  4657     {
  4658       char mpath_a[MAX_PATH];
  4659 
  4660       filename_to_ansi (mpath, mpath_a);
  4661       if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
  4662         res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
  4663       if (res < 0)
  4664         res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
  4665     }
  4666 
  4667   return res;
  4668 }
  4669 
  4670 /* This is not currently used, but might be needed again at some
  4671    point; DO NOT DELETE!  */
  4672 #if 0
  4673 int
  4674 openat (int fd, const char * path, int oflag, int mode)
  4675 {
  4676   /* Rely on a hack: an open directory is modeled as file descriptor 0,
  4677      as in fstatat.  FIXME: Add proper support for openat.  */
  4678   char fullname[MAX_UTF8_PATH];
  4679 
  4680   if (fd != AT_FDCWD)
  4681     {
  4682       if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, path)
  4683           < 0)
  4684         {
  4685           errno = ENAMETOOLONG;
  4686           return -1;
  4687         }
  4688       path = fullname;
  4689     }
  4690 
  4691   return sys_open (path, oflag, mode);
  4692 }
  4693 #endif
  4694 
  4695 int
  4696 fchmod (int fd, mode_t mode)
  4697 {
  4698   return 0;
  4699 }
  4700 
  4701 int
  4702 fchmodat (int fd, char const *path, mode_t mode, int flags)
  4703 {
  4704   /* Rely on a hack: an open directory is modeled as file descriptor 0,
  4705      as in fstatat.  FIXME: Add proper support for fchmodat.  */
  4706   char fullname[MAX_UTF8_PATH];
  4707 
  4708   if (fd != AT_FDCWD)
  4709     {
  4710       if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, path)
  4711           < 0)
  4712         {
  4713           errno = ENAMETOOLONG;
  4714           return -1;
  4715         }
  4716       path = fullname;
  4717     }
  4718 
  4719   return
  4720     flags == AT_SYMLINK_NOFOLLOW ? lchmod (path, mode) : sys_chmod (path, mode);
  4721 }
  4722 
  4723 int
  4724 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
  4725 {
  4726   BOOL result;
  4727   char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
  4728   int newname_dev;
  4729   int oldname_dev;
  4730   bool have_temp_a = false;
  4731 
  4732   /* MoveFile on Windows 95 doesn't correctly change the short file name
  4733      alias in a number of circumstances (it is not easy to predict when
  4734      just by looking at oldname and newname, unfortunately).  In these
  4735      cases, renaming through a temporary name avoids the problem.
  4736 
  4737      A second problem on Windows 95 is that renaming through a temp name when
  4738      newname is uppercase fails (the final long name ends up in
  4739      lowercase, although the short alias might be uppercase) UNLESS the
  4740      long temp name is not 8.3.
  4741 
  4742      So, on Windows 95 we always rename through a temp name, and we make sure
  4743      the temp name has a long extension to ensure correct renaming.  */
  4744 
  4745   strcpy (temp, map_w32_filename (oldname, NULL));
  4746 
  4747   /* volume_info is set indirectly by map_w32_filename.  */
  4748   oldname_dev = volume_info.serialnum;
  4749 
  4750   if (os_subtype == OS_SUBTYPE_9X)
  4751     {
  4752       char * o;
  4753       char * p;
  4754       int    i = 0;
  4755       char oldname_a[MAX_PATH];
  4756 
  4757       oldname = map_w32_filename (oldname, NULL);
  4758       filename_to_ansi (oldname, oldname_a);
  4759       filename_to_ansi (temp, temp_a);
  4760       if ((o = strrchr (oldname_a, '\\')))
  4761         o++;
  4762       else
  4763         o = (char *) oldname_a;
  4764 
  4765       if ((p = strrchr (temp_a, '\\')))
  4766         p++;
  4767       else
  4768         p = temp_a;
  4769 
  4770       do
  4771         {
  4772           /* Force temp name to require a manufactured 8.3 alias - this
  4773              seems to make the second rename work properly.  */
  4774           sprintf (p, "_.%s.%d", o, i);
  4775           i++;
  4776           result = rename (oldname_a, temp_a);
  4777         }
  4778       /* This loop must surely terminate!  */
  4779       while (result < 0 && errno == EEXIST);
  4780       if (result < 0)
  4781         return -1;
  4782       have_temp_a = true;
  4783     }
  4784 
  4785   /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
  4786      (at least if it is a file; don't do this for directories).
  4787 
  4788      Since we mustn't do this if we are just changing the case of the
  4789      file name (we would end up deleting the file we are trying to
  4790      rename!), we let rename detect if the destination file already
  4791      exists - that way we avoid the possible pitfalls of trying to
  4792      determine ourselves whether two names really refer to the same
  4793      file, which is not always possible in the general case.  (Consider
  4794      all the permutations of shared or subst'd drives, etc.)  */
  4795 
  4796   newname = map_w32_filename (newname, NULL);
  4797 
  4798   /* volume_info is set indirectly by map_w32_filename.  */
  4799   newname_dev = volume_info.serialnum;
  4800 
  4801   if (w32_unicode_filenames)
  4802     {
  4803       wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
  4804 
  4805       filename_to_utf16 (temp, temp_w);
  4806       filename_to_utf16 (newname, newname_w);
  4807       result = _wrename (temp_w, newname_w);
  4808       if (result < 0)
  4809         {
  4810           DWORD w32err = GetLastError ();
  4811 
  4812           if (errno == EACCES
  4813               && newname_dev != oldname_dev)
  4814             {
  4815               DWORD attributes;
  4816               /* The implementation of `rename' on Windows does not return
  4817                  errno = EXDEV when you are moving a directory to a
  4818                  different storage device (ex. logical disk).  It returns
  4819                  EACCES instead.  So here we handle such situations and
  4820                  return EXDEV.  */
  4821               if ((attributes = GetFileAttributesW (temp_w)) != -1
  4822                   && (attributes & FILE_ATTRIBUTE_DIRECTORY))
  4823                 errno = EXDEV;
  4824             }
  4825           else if (errno == EEXIST && force)
  4826             {
  4827               DWORD attributes_old;
  4828               DWORD attributes_new;
  4829 
  4830               if (_wchmod (newname_w, 0666) != 0)
  4831                 return result;
  4832               attributes_old = GetFileAttributesW (temp_w);
  4833               attributes_new = GetFileAttributesW (newname_w);
  4834               if (attributes_old != -1 && attributes_new != -1
  4835                   && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
  4836                       != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
  4837                 {
  4838                   if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4839                     errno = ENOTDIR;
  4840                   else
  4841                     errno = EISDIR;
  4842                   return -1;
  4843                 }
  4844               if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4845                 {
  4846                   if (_wrmdir (newname_w) != 0)
  4847                     return result;
  4848                 }
  4849               else if (_wunlink (newname_w) != 0)
  4850                 return result;
  4851               result = _wrename (temp_w, newname_w);
  4852             }
  4853           else if (w32err == ERROR_PRIVILEGE_NOT_HELD
  4854                    && is_symlink (temp))
  4855             {
  4856               /* This is Windows prohibiting the user from creating a
  4857                  symlink in another place, since that requires
  4858                  privileges.  */
  4859               errno = EPERM;
  4860             }
  4861         }
  4862     }
  4863   else
  4864     {
  4865       char newname_a[MAX_PATH];
  4866 
  4867       if (!have_temp_a)
  4868         filename_to_ansi (temp, temp_a);
  4869       filename_to_ansi (newname, newname_a);
  4870       result = rename (temp_a, newname_a);
  4871       if (result < 0)
  4872         {
  4873           DWORD w32err = GetLastError ();
  4874 
  4875           if (errno == EACCES
  4876               && newname_dev != oldname_dev)
  4877             {
  4878               DWORD attributes;
  4879               if ((attributes = GetFileAttributesA (temp_a)) != -1
  4880                   && (attributes & FILE_ATTRIBUTE_DIRECTORY))
  4881                 errno = EXDEV;
  4882             }
  4883           else if (errno == EEXIST && force)
  4884             {
  4885               DWORD attributes_old;
  4886               DWORD attributes_new;
  4887 
  4888               if (_chmod (newname_a, 0666) != 0)
  4889                 return result;
  4890               attributes_old = GetFileAttributesA (temp_a);
  4891               attributes_new = GetFileAttributesA (newname_a);
  4892               if (attributes_old != -1 && attributes_new != -1
  4893                   && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
  4894                       != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
  4895                 {
  4896                   if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4897                     errno = ENOTDIR;
  4898                   else
  4899                     errno = EISDIR;
  4900                   return -1;
  4901                 }
  4902               if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4903                 {
  4904                   if (_rmdir (newname_a) != 0)
  4905                     return result;
  4906                 }
  4907               else if (_unlink (newname_a) != 0)
  4908                 return result;
  4909               result = rename (temp_a, newname_a);
  4910             }
  4911           else if (w32err == ERROR_PRIVILEGE_NOT_HELD
  4912                    && is_symlink (temp))
  4913             errno = EPERM;
  4914         }
  4915     }
  4916 
  4917   return result;
  4918 }
  4919 
  4920 int
  4921 sys_rename (char const *old, char const *new)
  4922 {
  4923   return sys_rename_replace (old, new, TRUE);
  4924 }
  4925 
  4926 int
  4927 sys_rmdir (const char * path)
  4928 {
  4929   path = map_w32_filename (path, NULL);
  4930 
  4931   if (w32_unicode_filenames)
  4932     {
  4933       wchar_t path_w[MAX_PATH];
  4934 
  4935       filename_to_utf16 (path, path_w);
  4936       return _wrmdir (path_w);
  4937     }
  4938   else
  4939     {
  4940       char path_a[MAX_PATH];
  4941 
  4942       filename_to_ansi (path, path_a);
  4943       return _rmdir (path_a);
  4944     }
  4945 }
  4946 
  4947 int
  4948 sys_unlink (const char * path)
  4949 {
  4950   int rmstatus, e;
  4951 
  4952   path = map_w32_filename (path, NULL);
  4953 
  4954   if (w32_unicode_filenames)
  4955     {
  4956       wchar_t path_w[MAX_PATH];
  4957 
  4958       filename_to_utf16 (path, path_w);
  4959       /* On Unix, unlink works without write permission.  */
  4960       _wchmod (path_w, 0666);
  4961       rmstatus = _wunlink (path_w);
  4962       e = errno;
  4963       /* Symlinks to directories can only be deleted by _rmdir;
  4964          _unlink returns EACCES.  */
  4965       if (rmstatus != 0
  4966           && errno == EACCES
  4967           && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4968         rmstatus = _wrmdir (path_w);
  4969       else
  4970         errno = e;
  4971     }
  4972   else
  4973     {
  4974       char path_a[MAX_PATH];
  4975 
  4976       filename_to_ansi (path, path_a);
  4977       _chmod (path_a, 0666);
  4978       rmstatus = _unlink (path_a);
  4979       e = errno;
  4980       if (rmstatus != 0
  4981           && errno == EACCES
  4982           && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
  4983         rmstatus = _rmdir (path_a);
  4984       else
  4985         errno = e;
  4986     }
  4987 
  4988   return rmstatus;
  4989 }
  4990 
  4991 static FILETIME utc_base_ft;
  4992 static ULONGLONG utc_base;  /* In 100ns units */
  4993 static int init = 0;
  4994 
  4995 #define FILETIME_TO_U64(result, ft)        \
  4996   do {                                     \
  4997     ULARGE_INTEGER uiTemp;                 \
  4998     uiTemp.LowPart = (ft).dwLowDateTime;   \
  4999     uiTemp.HighPart = (ft).dwHighDateTime; \
  5000     result = uiTemp.QuadPart;              \
  5001   } while (0)
  5002 
  5003 static void
  5004 initialize_utc_base (void)
  5005 {
  5006   /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
  5007   SYSTEMTIME st;
  5008 
  5009   st.wYear = 1970;
  5010   st.wMonth = 1;
  5011   st.wDay = 1;
  5012   st.wHour = 0;
  5013   st.wMinute = 0;
  5014   st.wSecond = 0;
  5015   st.wMilliseconds = 0;
  5016 
  5017   SystemTimeToFileTime (&st, &utc_base_ft);
  5018   FILETIME_TO_U64 (utc_base, utc_base_ft);
  5019 }
  5020 
  5021 static time_t
  5022 convert_time (FILETIME ft)
  5023 {
  5024   ULONGLONG tmp;
  5025 
  5026   if (!init)
  5027     {
  5028       initialize_utc_base ();
  5029       init = 1;
  5030     }
  5031 
  5032   if (CompareFileTime (&ft, &utc_base_ft) < 0)
  5033     return 0;
  5034 
  5035   FILETIME_TO_U64 (tmp, ft);
  5036   return (time_t) ((tmp - utc_base) / 10000000L);
  5037 }
  5038 
  5039 static void
  5040 convert_from_timespec (struct timespec time, FILETIME * pft)
  5041 {
  5042   ULARGE_INTEGER tmp;
  5043 
  5044   if (!init)
  5045     {
  5046       initialize_utc_base ();
  5047       init = 1;
  5048     }
  5049 
  5050   /* time in 100ns units since 1-Jan-1601 */
  5051   tmp.QuadPart =
  5052     (ULONGLONG) time.tv_sec * 10000000L + time.tv_nsec / 100 + utc_base;
  5053   pft->dwHighDateTime = tmp.HighPart;
  5054   pft->dwLowDateTime = tmp.LowPart;
  5055 }
  5056 
  5057 static PSECURITY_DESCRIPTOR
  5058 get_file_security_desc_by_handle (HANDLE h)
  5059 {
  5060   PSECURITY_DESCRIPTOR psd = NULL;
  5061   DWORD err;
  5062   SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
  5063     | GROUP_SECURITY_INFORMATION  /* | DACL_SECURITY_INFORMATION */ ;
  5064 
  5065   err = get_security_info (h, SE_FILE_OBJECT, si,
  5066                            NULL, NULL, NULL, NULL, &psd);
  5067   if (err != ERROR_SUCCESS)
  5068     return NULL;
  5069 
  5070   return psd;
  5071 }
  5072 
  5073 static PSECURITY_DESCRIPTOR
  5074 get_file_security_desc_by_name (const char *fname)
  5075 {
  5076   PSECURITY_DESCRIPTOR psd = NULL;
  5077   DWORD sd_len, err;
  5078   SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
  5079     | GROUP_SECURITY_INFORMATION  /* | DACL_SECURITY_INFORMATION */ ;
  5080 
  5081   if (!get_file_security (fname, si, psd, 0, &sd_len))
  5082     {
  5083       err = GetLastError ();
  5084       if (err != ERROR_INSUFFICIENT_BUFFER)
  5085         return NULL;
  5086     }
  5087 
  5088   psd = xmalloc (sd_len);
  5089   if (!get_file_security (fname, si, psd, sd_len, &sd_len))
  5090     {
  5091       xfree (psd);
  5092       return NULL;
  5093     }
  5094 
  5095   return psd;
  5096 }
  5097 
  5098 static DWORD
  5099 get_rid (PSID sid)
  5100 {
  5101   unsigned n_subauthorities;
  5102 
  5103   /* Use the last sub-authority value of the RID, the relative
  5104      portion of the SID, as user/group ID. */
  5105   n_subauthorities = *get_sid_sub_authority_count (sid);
  5106   if (n_subauthorities < 1)
  5107     return 0;   /* the "World" RID */
  5108   return *get_sid_sub_authority (sid, n_subauthorities - 1);
  5109 }
  5110 
  5111 /* Caching SID and account values for faster lokup.  */
  5112 
  5113 struct w32_id {
  5114   unsigned rid;
  5115   struct w32_id *next;
  5116   char name[GNLEN+1];
  5117   unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
  5118 };
  5119 
  5120 static struct w32_id *w32_idlist;
  5121 
  5122 static int
  5123 w32_cached_id (PSID sid, unsigned *id, char *name)
  5124 {
  5125   struct w32_id *tail, *found;
  5126 
  5127   for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
  5128     {
  5129       if (equal_sid ((PSID)tail->sid, sid))
  5130         {
  5131           found = tail;
  5132           break;
  5133         }
  5134     }
  5135   if (found)
  5136     {
  5137       *id = found->rid;
  5138       strcpy (name, found->name);
  5139       return 1;
  5140     }
  5141   else
  5142     return 0;
  5143 }
  5144 
  5145 static void
  5146 w32_add_to_cache (PSID sid, unsigned id, char *name)
  5147 {
  5148   DWORD sid_len;
  5149   struct w32_id *new_entry;
  5150 
  5151   /* We don't want to leave behind stale cache from when Emacs was
  5152      dumped.  */
  5153   if (initialized)
  5154     {
  5155       sid_len = get_length_sid (sid);
  5156       new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
  5157       if (new_entry)
  5158         {
  5159           new_entry->rid = id;
  5160           strcpy (new_entry->name, name);
  5161           copy_sid (sid_len, (PSID)new_entry->sid, sid);
  5162           new_entry->next = w32_idlist;
  5163           w32_idlist = new_entry;
  5164         }
  5165     }
  5166 }
  5167 
  5168 #define UID 1
  5169 #define GID 2
  5170 
  5171 static int
  5172 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
  5173 {
  5174   PSID sid = NULL;
  5175   BOOL dflt;
  5176   SID_NAME_USE ignore;
  5177   char name[UNLEN+1];
  5178   DWORD name_len = sizeof (name);
  5179   char domain[1024];
  5180   DWORD domain_len = sizeof (domain);
  5181   int use_dflt = 0;
  5182   int result;
  5183 
  5184   if (what == UID)
  5185     result = get_security_descriptor_owner (psd, &sid, &dflt);
  5186   else if (what == GID)
  5187     result = get_security_descriptor_group (psd, &sid, &dflt);
  5188   else
  5189     result = 0;
  5190 
  5191   if (!result || !is_valid_sid (sid))
  5192     use_dflt = 1;
  5193   else if (!w32_cached_id (sid, id, nm))
  5194     {
  5195       if (!lookup_account_sid (NULL, sid, name, &name_len,
  5196                                domain, &domain_len, &ignore)
  5197           || name_len > UNLEN+1)
  5198         use_dflt = 1;
  5199       else
  5200         {
  5201           *id = get_rid (sid);
  5202           strcpy (nm, name);
  5203           w32_add_to_cache (sid, *id, name);
  5204         }
  5205     }
  5206   return use_dflt;
  5207 }
  5208 
  5209 static void
  5210 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
  5211 {
  5212   int dflt_usr = 0, dflt_grp = 0;
  5213 
  5214   if (!psd)
  5215     {
  5216       dflt_usr = 1;
  5217       dflt_grp = 1;
  5218     }
  5219   else
  5220     {
  5221       if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
  5222         dflt_usr = 1;
  5223       if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
  5224         dflt_grp = 1;
  5225     }
  5226   /* Consider files to belong to current user/group, if we cannot get
  5227      more accurate information.  */
  5228   if (dflt_usr)
  5229     {
  5230       st->st_uid = dflt_passwd.pw_uid;
  5231       strcpy (st->st_uname, dflt_passwd.pw_name);
  5232     }
  5233   if (dflt_grp)
  5234     {
  5235       st->st_gid = dflt_passwd.pw_gid;
  5236       strcpy (st->st_gname, dflt_group.gr_name);
  5237     }
  5238 }
  5239 
  5240 /* Return non-zero if NAME is a potentially slow filesystem.  */
  5241 int is_slow_fs (const char *);
  5242 
  5243 int
  5244 is_slow_fs (const char *name)
  5245 {
  5246   char drive_root[4];
  5247   UINT devtype;
  5248 
  5249   if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
  5250     devtype = DRIVE_REMOTE;        /* assume UNC name is remote */
  5251   else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
  5252     devtype = GetDriveType (NULL); /* use root of current drive */
  5253   else
  5254     {
  5255       /* GetDriveType needs the root directory of the drive.  */
  5256       strncpy (drive_root, name, 2);
  5257       drive_root[2] = '\\';
  5258       drive_root[3] = '\0';
  5259       devtype = GetDriveType (drive_root);
  5260     }
  5261   return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
  5262 }
  5263 
  5264 /* If this is non-zero, the caller wants accurate information about
  5265    file's owner and group, which could be expensive to get.  dired.c
  5266    uses this flag when needed for the job at hand.  */
  5267 int w32_stat_get_owner_group;
  5268 
  5269 /* MSVC stat function can't cope with UNC names and has other bugs, so
  5270    replace it with our own.  This also allows us to calculate consistent
  5271    inode values and owner/group without hacks in the main Emacs code,
  5272    and support file names encoded in UTF-8. */
  5273 
  5274 static int
  5275 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
  5276 {
  5277   char *name, *save_name, *r;
  5278   WIN32_FIND_DATAW wfd_w;
  5279   WIN32_FIND_DATAA wfd_a;
  5280   HANDLE fh;
  5281   unsigned __int64 fake_inode = 0;
  5282   int permission;
  5283   int len;
  5284   int rootdir = FALSE;
  5285   PSECURITY_DESCRIPTOR psd = NULL;
  5286   int is_a_symlink = 0;
  5287   DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
  5288   DWORD access_rights = 0;
  5289   DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
  5290   FILETIME ctime, atime, wtime;
  5291   wchar_t name_w[MAX_PATH];
  5292   char name_a[MAX_PATH];
  5293 
  5294   if (path == NULL || buf == NULL)
  5295     {
  5296       errno = EFAULT;
  5297       return -1;
  5298     }
  5299 
  5300   save_name = name = (char *) map_w32_filename (path, &path);
  5301   /* Must be valid filename, no wild cards or other invalid
  5302      characters.  */
  5303   if (strpbrk (name, "*?|<>\""))
  5304     {
  5305       errno = ENOENT;
  5306       return -1;
  5307     }
  5308 
  5309   len = strlen (name);
  5310   /* Allocate 1 extra byte so that we could append a slash to a root
  5311      directory, down below.  */
  5312   name = strcpy (alloca (len + 2), name);
  5313 
  5314   /* Avoid a somewhat costly call to is_symlink if the filesystem
  5315      doesn't support symlinks.  */
  5316   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
  5317     is_a_symlink = is_symlink (name);
  5318 
  5319   /* Plan A: Open the file and get all the necessary information via
  5320      the resulting handle.  This solves several issues in one blow:
  5321 
  5322       . retrieves attributes for the target of a symlink, if needed
  5323       . gets attributes of root directories and symlinks pointing to
  5324         root directories, thus avoiding the need for special-casing
  5325         these and detecting them by examining the file-name format
  5326       . retrieves more accurate attributes (e.g., non-zero size for
  5327         some directories, esp. directories that are junction points)
  5328       . correctly resolves "c:/..", "/.." and similar file names
  5329       . avoids run-time penalties for 99% of use cases
  5330 
  5331      Plan A is always tried first, unless the user asked not to (but
  5332      if the file is a symlink and we need to follow links, we try Plan
  5333      A even if the user asked not to).
  5334 
  5335      If Plan A fails, we go to Plan B (below), where various
  5336      potentially expensive techniques must be used to handle "special"
  5337      files such as UNC volumes etc.  */
  5338   if (!(NILP (Vw32_get_true_file_attributes)
  5339         || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
  5340       /* Following symlinks requires getting the info by handle.  */
  5341       || (is_a_symlink && follow_symlinks))
  5342     {
  5343       BY_HANDLE_FILE_INFORMATION info;
  5344 
  5345       if (is_a_symlink && !follow_symlinks)
  5346         file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
  5347       /* READ_CONTROL access rights are required to get security info
  5348          by handle.  But if the OS doesn't support security in the
  5349          first place, we don't need to try.  */
  5350       if (is_windows_9x () != TRUE)
  5351         access_rights |= READ_CONTROL;
  5352 
  5353       if (w32_unicode_filenames)
  5354         {
  5355           filename_to_utf16 (name, name_w);
  5356           fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
  5357                            file_flags, NULL);
  5358           /* If CreateFile fails with READ_CONTROL, try again with
  5359              zero as access rights.  */
  5360           if (fh == INVALID_HANDLE_VALUE && access_rights)
  5361             fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
  5362                              file_flags, NULL);
  5363         }
  5364       else
  5365         {
  5366           filename_to_ansi (name, name_a);
  5367           fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
  5368                            file_flags, NULL);
  5369           if (fh == INVALID_HANDLE_VALUE && access_rights)
  5370             fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
  5371                              file_flags, NULL);
  5372         }
  5373       if (fh == INVALID_HANDLE_VALUE)
  5374         goto no_true_file_attributes;
  5375 
  5376       /* This is more accurate in terms of getting the correct number
  5377          of links, but is quite slow (it is noticeable when Emacs is
  5378          making a list of file name completions). */
  5379       if (GetFileInformationByHandle (fh, &info))
  5380         {
  5381           nlinks = info.nNumberOfLinks;
  5382           /* Might as well use file index to fake inode values, but this
  5383              is not guaranteed to be unique unless we keep a handle open
  5384              all the time (even then there are situations where it is
  5385              not unique).  Reputedly, there are at most 48 bits of info
  5386              (on NTFS, presumably less on FAT). */
  5387           fake_inode = info.nFileIndexHigh;
  5388           fake_inode <<= 32;
  5389           fake_inode += info.nFileIndexLow;
  5390           serialnum = info.dwVolumeSerialNumber;
  5391           fs_high = info.nFileSizeHigh;
  5392           fs_low  = info.nFileSizeLow;
  5393           ctime = info.ftCreationTime;
  5394           atime = info.ftLastAccessTime;
  5395           wtime = info.ftLastWriteTime;
  5396           fattrs = info.dwFileAttributes;
  5397         }
  5398       else
  5399         {
  5400           /* We don't go to Plan B here, because it's not clear that
  5401              it's a good idea.  The only known use case where
  5402              CreateFile succeeds, but GetFileInformationByHandle fails
  5403              (with ERROR_INVALID_FUNCTION) is for character devices
  5404              such as NUL, PRN, etc.  For these, switching to Plan B is
  5405              a net loss, because we lose the character device
  5406              attribute returned by GetFileType below (FindFirstFile
  5407              doesn't set that bit in the attributes), and the other
  5408              fields don't make sense for character devices anyway.
  5409              Emacs doesn't really care for non-file entities in the
  5410              context of l?stat, so neither do we.  */
  5411 
  5412           /* w32err is assigned so one could put a breakpoint here and
  5413              examine its value, when GetFileInformationByHandle
  5414              fails. */
  5415           DWORD w32err = GetLastError ();
  5416 
  5417           switch (w32err)
  5418             {
  5419             case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
  5420               errno = ENOENT;
  5421               return -1;
  5422             }
  5423         }
  5424 
  5425       /* Test for a symlink before testing for a directory, since
  5426          symlinks to directories have the directory bit set, but we
  5427          don't want them to appear as directories.  */
  5428       if (is_a_symlink && !follow_symlinks)
  5429         buf->st_mode = S_IFLNK;
  5430       else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
  5431         buf->st_mode = S_IFDIR;
  5432       else
  5433         {
  5434           DWORD ftype = GetFileType (fh);
  5435 
  5436           switch (ftype)
  5437             {
  5438             case FILE_TYPE_DISK:
  5439               buf->st_mode = S_IFREG;
  5440               break;
  5441             case FILE_TYPE_PIPE:
  5442               buf->st_mode = S_IFIFO;
  5443               break;
  5444             case FILE_TYPE_CHAR:
  5445             case FILE_TYPE_UNKNOWN:
  5446             default:
  5447               buf->st_mode = S_IFCHR;
  5448             }
  5449         }
  5450       /* We produce the fallback owner and group data, based on the
  5451          current user that runs Emacs, in the following cases:
  5452 
  5453           . caller didn't request owner and group info
  5454           . this is Windows 9X
  5455           . getting security by handle failed, and we need to produce
  5456             information for the target of a symlink (this is better
  5457             than producing a potentially misleading info about the
  5458             symlink itself)
  5459 
  5460          If getting security by handle fails, and we don't need to
  5461          resolve symlinks, we try getting security by name.  */
  5462       if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
  5463         get_file_owner_and_group (NULL, buf);
  5464       else
  5465         {
  5466           psd = get_file_security_desc_by_handle (fh);
  5467           if (psd)
  5468             {
  5469               get_file_owner_and_group (psd, buf);
  5470               LocalFree (psd);
  5471             }
  5472           else if (!(is_a_symlink && follow_symlinks))
  5473             {
  5474               psd = get_file_security_desc_by_name (name);
  5475               get_file_owner_and_group (psd, buf);
  5476               xfree (psd);
  5477             }
  5478           else
  5479             get_file_owner_and_group (NULL, buf);
  5480         }
  5481       CloseHandle (fh);
  5482     }
  5483   else
  5484     {
  5485     no_true_file_attributes:
  5486       /* Plan B: Either getting a handle on the file failed, or the
  5487          caller explicitly asked us to not bother making this
  5488          information more accurate.
  5489 
  5490          Implementation note: In Plan B, we never bother to resolve
  5491          symlinks, even if we got here because we tried Plan A and
  5492          failed.  That's because, even if the caller asked for extra
  5493          precision by setting Vw32_get_true_file_attributes to t,
  5494          resolving symlinks requires acquiring a file handle to the
  5495          symlink, which we already know will fail.  And if the user
  5496          did not ask for extra precision, resolving symlinks will fly
  5497          in the face of that request, since the user then wants the
  5498          lightweight version of the code.  */
  5499       rootdir = (path >= save_name + len - 1
  5500                  && (IS_DIRECTORY_SEP (*path) || *path == 0));
  5501 
  5502       /* If name is "c:/.." or "/.." then stat "c:/" or "/".  */
  5503       r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
  5504       if (IS_DIRECTORY_SEP (r[0])
  5505           && r[1] == '.' && r[2] == '.' && r[3] == '\0')
  5506         r[1] = r[2] = '\0';
  5507 
  5508       /* Note: If NAME is a symlink to the root of a UNC volume
  5509          (i.e. "\\SERVER"), we will not detect that here, and we will
  5510          return data about the symlink as result of FindFirst below.
  5511          This is unfortunate, but that marginal use case does not
  5512          justify a call to chase_symlinks which would impose a penalty
  5513          on all the other use cases.  (We get here for symlinks to
  5514          roots of UNC volumes because CreateFile above fails for them,
  5515          unlike with symlinks to root directories X:\ of drives.)  */
  5516       if (is_unc_volume (name))
  5517         {
  5518           fattrs = unc_volume_file_attributes (name);
  5519           if (fattrs == -1)
  5520             return -1;
  5521 
  5522           ctime = atime = wtime = utc_base_ft;
  5523         }
  5524       else if (rootdir)
  5525         {
  5526           /* Make sure root directories end in a slash.  */
  5527           if (!IS_DIRECTORY_SEP (name[len-1]))
  5528             strcpy (name + len, "\\");
  5529           if (GetDriveType (name) < 2)
  5530             {
  5531               errno = ENOENT;
  5532               return -1;
  5533             }
  5534 
  5535           fattrs = FILE_ATTRIBUTE_DIRECTORY;
  5536           ctime = atime = wtime = utc_base_ft;
  5537         }
  5538       else
  5539         {
  5540           int have_wfd = -1;
  5541 
  5542           /* Make sure non-root directories do NOT end in a slash,
  5543              otherwise FindFirstFile might fail.  */
  5544           if (IS_DIRECTORY_SEP (name[len-1]))
  5545             name[len - 1] = 0;
  5546 
  5547           /* (This is hacky, but helps when doing file completions on
  5548              network drives.)  Optimize by using information available from
  5549              active readdir if possible.  */
  5550           len = strlen (dir_pathname);
  5551           if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
  5552             len--;
  5553           if (dir_find_handle != INVALID_HANDLE_VALUE
  5554               && last_dir_find_data != -1
  5555               && !(is_a_symlink && follow_symlinks)
  5556               /* The 2 file-name comparisons below support only ASCII
  5557                  characters, and will lose (compare not equal) when
  5558                  the file names include non-ASCII characters that are
  5559                  the same but for the case.  However, doing this
  5560                  properly involves: (a) converting both file names to
  5561                  UTF-16, (b) lower-casing both names using CharLowerW,
  5562                  and (c) comparing the results; this would be quite a
  5563                  bit slower, whereas Plan B is for users who want
  5564                  lightweight albeit inaccurate version of 'stat'.  */
  5565               && c_strncasecmp (save_name, dir_pathname, len) == 0
  5566               && IS_DIRECTORY_SEP (name[len])
  5567               && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
  5568             {
  5569               have_wfd = last_dir_find_data;
  5570               /* This was the last entry returned by readdir.  */
  5571               if (last_dir_find_data == DIR_FIND_DATA_W)
  5572                 wfd_w = dir_find_data_w;
  5573               else
  5574                 wfd_a = dir_find_data_a;
  5575             }
  5576           else
  5577             {
  5578               logon_network_drive (name);
  5579 
  5580               if (w32_unicode_filenames)
  5581                 {
  5582                   filename_to_utf16 (name, name_w);
  5583                   fh = FindFirstFileW (name_w, &wfd_w);
  5584                   have_wfd = DIR_FIND_DATA_W;
  5585                 }
  5586               else
  5587                 {
  5588                   filename_to_ansi (name, name_a);
  5589                   /* If NAME includes characters not representable by
  5590                      the current ANSI codepage, filename_to_ansi
  5591                      usually replaces them with a '?'.  We don't want
  5592                      to let FindFirstFileA interpret those as wildcards,
  5593                      and "succeed", returning us data from some random
  5594                      file in the same directory.  */
  5595                   if (_mbspbrk (name_a, "?"))
  5596                     fh = INVALID_HANDLE_VALUE;
  5597                   else
  5598                     fh = FindFirstFileA (name_a, &wfd_a);
  5599                   have_wfd = DIR_FIND_DATA_A;
  5600                 }
  5601               if (fh == INVALID_HANDLE_VALUE)
  5602                 {
  5603                   errno = ENOENT;
  5604                   return -1;
  5605                 }
  5606               FindClose (fh);
  5607             }
  5608           /* Note: if NAME is a symlink, the information we get from
  5609              FindFirstFile is for the symlink, not its target.  */
  5610           if (have_wfd == DIR_FIND_DATA_W)
  5611             {
  5612               fattrs = wfd_w.dwFileAttributes;
  5613               ctime = wfd_w.ftCreationTime;
  5614               atime = wfd_w.ftLastAccessTime;
  5615               wtime = wfd_w.ftLastWriteTime;
  5616               fs_high = wfd_w.nFileSizeHigh;
  5617               fs_low = wfd_w.nFileSizeLow;
  5618             }
  5619           else
  5620             {
  5621               fattrs = wfd_a.dwFileAttributes;
  5622               ctime = wfd_a.ftCreationTime;
  5623               atime = wfd_a.ftLastAccessTime;
  5624               wtime = wfd_a.ftLastWriteTime;
  5625               fs_high = wfd_a.nFileSizeHigh;
  5626               fs_low = wfd_a.nFileSizeLow;
  5627             }
  5628           fake_inode = 0;
  5629           nlinks = 1;
  5630           serialnum = volume_info.serialnum;
  5631         }
  5632       if (is_a_symlink && !follow_symlinks)
  5633         buf->st_mode = S_IFLNK;
  5634       else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
  5635         buf->st_mode = S_IFDIR;
  5636       else
  5637         buf->st_mode = S_IFREG;
  5638 
  5639       get_file_owner_and_group (NULL, buf);
  5640     }
  5641 
  5642   buf->st_ino = fake_inode;
  5643 
  5644   buf->st_dev = serialnum;
  5645   buf->st_rdev = serialnum;
  5646 
  5647   buf->st_size = fs_high;
  5648   buf->st_size <<= 32;
  5649   buf->st_size += fs_low;
  5650   buf->st_nlink = nlinks;
  5651 
  5652   /* Convert timestamps to Unix format. */
  5653   buf->st_mtime = convert_time (wtime);
  5654   buf->st_atime = convert_time (atime);
  5655   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
  5656   buf->st_ctime = convert_time (ctime);
  5657   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
  5658 
  5659   /* determine rwx permissions */
  5660   if (is_a_symlink && !follow_symlinks)
  5661     permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
  5662   else
  5663     {
  5664       if (fattrs & FILE_ATTRIBUTE_READONLY)
  5665         permission = S_IREAD;
  5666       else
  5667         permission = S_IREAD | S_IWRITE;
  5668 
  5669       if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
  5670         permission |= S_IEXEC;
  5671       else if (is_exec (name))
  5672         permission |= S_IEXEC;
  5673     }
  5674 
  5675   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
  5676 
  5677   return 0;
  5678 }
  5679 
  5680 int
  5681 stat (const char * path, struct stat * buf)
  5682 {
  5683   return stat_worker (path, buf, 1);
  5684 }
  5685 
  5686 int
  5687 lstat (const char * path, struct stat * buf)
  5688 {
  5689   return stat_worker (path, buf, 0);
  5690 }
  5691 
  5692 int
  5693 fstatat (int fd, char const *name, struct stat *st, int flags)
  5694 {
  5695   /* Rely on a hack: an open directory is modeled as file descriptor 0.
  5696      This is good enough for the current usage in Emacs, but is fragile.
  5697 
  5698      FIXME: Add proper support for fdopendir, fstatat, readlinkat.
  5699      Gnulib does this and can serve as a model.  */
  5700   char fullname[MAX_UTF8_PATH];
  5701 
  5702   if (fd != AT_FDCWD)
  5703     {
  5704       char lastc = dir_pathname[strlen (dir_pathname) - 1];
  5705 
  5706       if (_snprintf (fullname, sizeof fullname, "%s%s%s",
  5707                      dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
  5708           < 0)
  5709         {
  5710           errno = ENAMETOOLONG;
  5711           return -1;
  5712         }
  5713       name = fullname;
  5714     }
  5715 
  5716   return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
  5717 }
  5718 
  5719 /* Provide fstat and utimensat as well as stat for consistent handling
  5720    of file timestamps. */
  5721 int
  5722 fstat (int desc, struct stat * buf)
  5723 {
  5724   HANDLE fh = (HANDLE) _get_osfhandle (desc);
  5725   BY_HANDLE_FILE_INFORMATION info;
  5726   unsigned __int64 fake_inode;
  5727   int permission;
  5728 
  5729   switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
  5730     {
  5731     case FILE_TYPE_DISK:
  5732       buf->st_mode = S_IFREG;
  5733       if (!GetFileInformationByHandle (fh, &info))
  5734         {
  5735           errno = EACCES;
  5736           return -1;
  5737         }
  5738       break;
  5739     case FILE_TYPE_PIPE:
  5740       buf->st_mode = S_IFIFO;
  5741       goto non_disk;
  5742     case FILE_TYPE_CHAR:
  5743     case FILE_TYPE_UNKNOWN:
  5744     default:
  5745       buf->st_mode = S_IFCHR;
  5746     non_disk:
  5747       memset (&info, 0, sizeof (info));
  5748       info.dwFileAttributes = 0;
  5749       info.ftCreationTime = utc_base_ft;
  5750       info.ftLastAccessTime = utc_base_ft;
  5751       info.ftLastWriteTime = utc_base_ft;
  5752     }
  5753 
  5754   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  5755       buf->st_mode = S_IFDIR;
  5756 
  5757   buf->st_nlink = info.nNumberOfLinks;
  5758   /* Might as well use file index to fake inode values, but this
  5759      is not guaranteed to be unique unless we keep a handle open
  5760      all the time (even then there are situations where it is
  5761      not unique).  Reputedly, there are at most 48 bits of info
  5762      (on NTFS, presumably less on FAT). */
  5763   fake_inode = info.nFileIndexHigh;
  5764   fake_inode <<= 32;
  5765   fake_inode += info.nFileIndexLow;
  5766 
  5767   /* MSVC defines _ino_t to be short; other libc's might not.  */
  5768   if (sizeof (buf->st_ino) == 2)
  5769     buf->st_ino = fake_inode ^ (fake_inode >> 16);
  5770   else
  5771     buf->st_ino = fake_inode;
  5772 
  5773   /* If the caller so requested, get the true file owner and group.
  5774      Otherwise, consider the file to belong to the current user.  */
  5775   if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
  5776     get_file_owner_and_group (NULL, buf);
  5777   else
  5778     {
  5779       PSECURITY_DESCRIPTOR psd = NULL;
  5780 
  5781       psd = get_file_security_desc_by_handle (fh);
  5782       if (psd)
  5783         {
  5784           get_file_owner_and_group (psd, buf);
  5785           LocalFree (psd);
  5786         }
  5787       else
  5788         get_file_owner_and_group (NULL, buf);
  5789     }
  5790 
  5791   buf->st_dev = info.dwVolumeSerialNumber;
  5792   buf->st_rdev = info.dwVolumeSerialNumber;
  5793 
  5794   buf->st_size = info.nFileSizeHigh;
  5795   buf->st_size <<= 32;
  5796   buf->st_size += info.nFileSizeLow;
  5797 
  5798   /* Convert timestamps to Unix format. */
  5799   buf->st_mtime = convert_time (info.ftLastWriteTime);
  5800   buf->st_atime = convert_time (info.ftLastAccessTime);
  5801   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
  5802   buf->st_ctime = convert_time (info.ftCreationTime);
  5803   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
  5804 
  5805   /* determine rwx permissions */
  5806   if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  5807     permission = S_IREAD;
  5808   else
  5809     permission = S_IREAD | S_IWRITE;
  5810 
  5811   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  5812     permission |= S_IEXEC;
  5813   else
  5814     {
  5815 #if 0 /* no way of knowing the filename */
  5816       char * p = strrchr (name, '.');
  5817       if (p != NULL &&
  5818           (xstrcasecmp (p, ".exe") == 0 ||
  5819            xstrcasecmp (p, ".com") == 0 ||
  5820            xstrcasecmp (p, ".bat") == 0 ||
  5821            xstrcasecmp (p, ".cmd") == 0))
  5822         permission |= S_IEXEC;
  5823 #endif
  5824     }
  5825 
  5826   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
  5827 
  5828   return 0;
  5829 }
  5830 
  5831 /* Emulate utimensat.  */
  5832 
  5833 int
  5834 utimensat (int fd, const char *name, const struct timespec times[2], int flag)
  5835 {
  5836   struct timespec ltimes[2];
  5837   HANDLE fh;
  5838   FILETIME mtime;
  5839   FILETIME atime;
  5840   DWORD flags_and_attrs = FILE_FLAG_BACKUP_SEMANTICS;
  5841 
  5842   /* Rely on a hack: an open directory is modeled as file descriptor 0.
  5843      This is good enough for the current usage in Emacs, but is fragile.
  5844 
  5845      FIXME: Add proper support for utimensat.
  5846      Gnulib does this and can serve as a model.  */
  5847   char fullname[MAX_UTF8_PATH];
  5848 
  5849   if (fd != AT_FDCWD)
  5850     {
  5851       char lastc = dir_pathname[strlen (dir_pathname) - 1];
  5852 
  5853       if (_snprintf (fullname, sizeof fullname, "%s%s%s",
  5854                      dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
  5855           < 0)
  5856         {
  5857           errno = ENAMETOOLONG;
  5858           return -1;
  5859         }
  5860       name = fullname;
  5861     }
  5862 
  5863   if (times == NULL)
  5864     {
  5865       memset (ltimes, 0, sizeof (ltimes));
  5866       ltimes[0] = ltimes[1] = current_timespec ();
  5867     }
  5868   else
  5869     {
  5870       if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
  5871         return 0;               /* nothing to do */
  5872       if ((times[0].tv_nsec != UTIME_NOW && times[0].tv_nsec != UTIME_OMIT
  5873            && !(0 <= times[0].tv_nsec && times[0].tv_nsec < 1000000000))
  5874           || (times[1].tv_nsec != UTIME_NOW && times[1].tv_nsec != UTIME_OMIT
  5875               && !(0 <= times[1].tv_nsec && times[1].tv_nsec < 1000000000)))
  5876         {
  5877           errno = EINVAL;       /* reject invalid timespec values */
  5878           return -1;
  5879         }
  5880 
  5881       memcpy (ltimes, times, sizeof (ltimes));
  5882       if (ltimes[0].tv_nsec == UTIME_NOW)
  5883         ltimes[0] = current_timespec ();
  5884       if (ltimes[1].tv_nsec == UTIME_NOW)
  5885         ltimes[1] = current_timespec ();
  5886     }
  5887 
  5888   if (flag == AT_SYMLINK_NOFOLLOW)
  5889     flags_and_attrs |= FILE_FLAG_OPEN_REPARSE_POINT;
  5890   if (w32_unicode_filenames)
  5891     {
  5892       wchar_t name_utf16[MAX_PATH];
  5893 
  5894       if (filename_to_utf16 (name, name_utf16) != 0)
  5895         return -1;      /* errno set by filename_to_utf16 */
  5896 
  5897       /* Need write access to set times.  */
  5898       fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
  5899                         /* If NAME specifies a directory, FILE_SHARE_DELETE
  5900                            allows other processes to delete files inside it,
  5901                            while we have the directory open.  */
  5902                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  5903                         0, OPEN_EXISTING, flags_and_attrs, NULL);
  5904     }
  5905   else
  5906     {
  5907       char name_ansi[MAX_PATH];
  5908 
  5909       if (filename_to_ansi (name, name_ansi) != 0)
  5910         return -1;      /* errno set by filename_to_ansi */
  5911 
  5912       fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
  5913                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  5914                         0, OPEN_EXISTING, flags_and_attrs, NULL);
  5915     }
  5916   if (fh != INVALID_HANDLE_VALUE)
  5917     {
  5918       FILETIME *patime, *pmtime;
  5919       if (ltimes[0].tv_nsec == UTIME_OMIT)
  5920         patime = NULL;
  5921       else
  5922         {
  5923           convert_from_timespec (ltimes[0], &atime);
  5924           patime = &atime;
  5925         }
  5926       if (ltimes[1].tv_nsec == UTIME_OMIT)
  5927         pmtime = NULL;
  5928       else
  5929         {
  5930           convert_from_timespec (ltimes[1], &mtime);
  5931           pmtime = &mtime;
  5932         }
  5933       if (!SetFileTime (fh, NULL, patime, pmtime))
  5934         {
  5935           CloseHandle (fh);
  5936           errno = EACCES;
  5937           return -1;
  5938         }
  5939       CloseHandle (fh);
  5940     }
  5941   else
  5942     {
  5943       DWORD err = GetLastError ();
  5944 
  5945       switch (err)
  5946         {
  5947         case ERROR_FILE_NOT_FOUND:
  5948         case ERROR_PATH_NOT_FOUND:
  5949         case ERROR_INVALID_DRIVE:
  5950         case ERROR_BAD_NETPATH:
  5951         case ERROR_DEV_NOT_EXIST:
  5952           /* ERROR_INVALID_NAME is the error CreateFile sets when the
  5953              file name includes ?s, i.e. translation to ANSI failed.  */
  5954         case ERROR_INVALID_NAME:
  5955           errno = ENOENT;
  5956           break;
  5957         case ERROR_TOO_MANY_OPEN_FILES:
  5958           errno = ENFILE;
  5959           break;
  5960         case ERROR_ACCESS_DENIED:
  5961         case ERROR_SHARING_VIOLATION:
  5962           errno = EACCES;
  5963           break;
  5964         default:
  5965           errno = EINVAL;
  5966           break;
  5967         }
  5968       return -1;
  5969     }
  5970   return 0;
  5971 }
  5972 
  5973 int
  5974 sys_umask (int mode)
  5975 {
  5976   static int current_mask;
  5977   int retval, arg = 0;
  5978 
  5979   /* The only bit we really support is the write bit.  Files are
  5980      always readable on MS-Windows, and the execute bit does not exist
  5981      at all.  */
  5982   /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
  5983      to prevent access by other users on NTFS.  */
  5984   if ((mode & S_IWRITE) != 0)
  5985     arg |= S_IWRITE;
  5986 
  5987   retval = _umask (arg);
  5988   /* Merge into the return value the bits they've set the last time,
  5989      which msvcrt.dll ignores and never returns.  Emacs insists on its
  5990      notion of mask being identical to what we return.  */
  5991   retval |= (current_mask & ~S_IWRITE);
  5992   current_mask = mode;
  5993 
  5994   return retval;
  5995 }
  5996 
  5997 
  5998 /* Symlink-related functions.  */
  5999 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
  6000 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
  6001 #endif
  6002 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
  6003 #define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
  6004 #endif
  6005 
  6006 int
  6007 symlink (char const *filename, char const *linkname)
  6008 {
  6009   char linkfn[MAX_UTF8_PATH], *tgtfn;
  6010   /* The SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag is
  6011      supported from Windows 10 build 14972.  It is only supported if
  6012      Developer Mode is enabled, and is ignored if it isn't.  */
  6013   DWORD flags =
  6014     (os_subtype == OS_SUBTYPE_NT
  6015      && (w32_major_version > 10
  6016          || (w32_major_version == 10 && w32_build_number >= 14972)))
  6017     ? SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE : 0;
  6018   int dir_access, filename_ends_in_slash;
  6019 
  6020   /* Diagnostics follows Posix as much as possible.  */
  6021   if (filename == NULL || linkname == NULL)
  6022     {
  6023       errno = EFAULT;
  6024       return -1;
  6025     }
  6026   if (!*filename)
  6027     {
  6028       errno = ENOENT;
  6029       return -1;
  6030     }
  6031   if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
  6032     {
  6033       errno = ENAMETOOLONG;
  6034       return -1;
  6035     }
  6036 
  6037   strcpy (linkfn, map_w32_filename (linkname, NULL));
  6038   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
  6039     {
  6040       errno = EPERM;
  6041       return -1;
  6042     }
  6043 
  6044   /* Note: since empty FILENAME was already rejected, we can safely
  6045      refer to FILENAME[1].  */
  6046   if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
  6047     {
  6048       /* Non-absolute FILENAME is understood as being relative to
  6049          LINKNAME's directory.  We need to prepend that directory to
  6050          FILENAME to get correct results from faccessat below, since
  6051          otherwise it will interpret FILENAME relative to the
  6052          directory where the Emacs process runs.  Note that
  6053          make-symbolic-link always makes sure LINKNAME is a fully
  6054          expanded file name.  */
  6055       char tem[MAX_UTF8_PATH];
  6056       char *p = linkfn + strlen (linkfn);
  6057 
  6058       while (p > linkfn && !IS_ANY_SEP (p[-1]))
  6059         p--;
  6060       if (p > linkfn)
  6061         strncpy (tem, linkfn, p - linkfn);
  6062       strcpy (tem + (p - linkfn), filename);
  6063       dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
  6064     }
  6065   else
  6066     dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
  6067 
  6068   /* Since Windows distinguishes between symlinks to directories and
  6069      to files, we provide a kludgy feature: if FILENAME doesn't
  6070      exist, but ends in a slash, we create a symlink to directory.  If
  6071      FILENAME exists and is a directory, we always create a symlink to
  6072      directory.  */
  6073   filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
  6074   if (dir_access == 0 || filename_ends_in_slash)
  6075     flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
  6076 
  6077   tgtfn = (char *)map_w32_filename (filename, NULL);
  6078   if (filename_ends_in_slash)
  6079     tgtfn[strlen (tgtfn) - 1] = '\0';
  6080 
  6081   errno = 0;
  6082   if (!create_symbolic_link (linkfn, tgtfn, flags))
  6083     {
  6084       /* ENOSYS is set by create_symbolic_link, when it detects that
  6085          the OS doesn't support the CreateSymbolicLink API.  */
  6086       if (errno != ENOSYS)
  6087         {
  6088           DWORD w32err = GetLastError ();
  6089 
  6090           switch (w32err)
  6091             {
  6092               /* ERROR_SUCCESS is sometimes returned when LINKFN and
  6093                  TGTFN point to the same file name, go figure.  */
  6094             case ERROR_SUCCESS:
  6095             case ERROR_FILE_EXISTS:
  6096               errno = EEXIST;
  6097               break;
  6098             case ERROR_ACCESS_DENIED:
  6099               errno = EACCES;
  6100               break;
  6101             case ERROR_FILE_NOT_FOUND:
  6102             case ERROR_PATH_NOT_FOUND:
  6103             case ERROR_BAD_NETPATH:
  6104             case ERROR_INVALID_REPARSE_DATA:
  6105               errno = ENOENT;
  6106               break;
  6107             case ERROR_DIRECTORY:
  6108               errno = EISDIR;
  6109               break;
  6110             case ERROR_PRIVILEGE_NOT_HELD:
  6111             case ERROR_NOT_ALL_ASSIGNED:
  6112               errno = EPERM;
  6113               break;
  6114             case ERROR_DISK_FULL:
  6115               errno = ENOSPC;
  6116               break;
  6117             default:
  6118               errno = EINVAL;
  6119               break;
  6120             }
  6121         }
  6122       return -1;
  6123     }
  6124   return 0;
  6125 }
  6126 
  6127 /* A quick inexpensive test of whether FILENAME identifies a file that
  6128    is a symlink.  Returns non-zero if it is, zero otherwise.  FILENAME
  6129    must already be in the normalized form returned by
  6130    map_w32_filename.  If the symlink is to a directory, the
  6131    FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
  6132 
  6133    Note: for repeated operations on many files, it is best to test
  6134    whether the underlying volume actually supports symlinks, by
  6135    testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
  6136    avoid the call to this function if it doesn't.  That's because the
  6137    call to GetFileAttributes takes a non-negligible time, especially
  6138    on non-local or removable filesystems.  See stat_worker for an
  6139    example of how to do that.  */
  6140 static int
  6141 is_symlink (const char *filename)
  6142 {
  6143   DWORD attrs;
  6144   wchar_t filename_w[MAX_PATH];
  6145   char filename_a[MAX_PATH];
  6146   WIN32_FIND_DATAW wfdw;
  6147   WIN32_FIND_DATAA wfda;
  6148   HANDLE fh;
  6149   int attrs_mean_symlink;
  6150 
  6151   if (w32_unicode_filenames)
  6152     {
  6153       filename_to_utf16 (filename, filename_w);
  6154       attrs = GetFileAttributesW (filename_w);
  6155     }
  6156   else
  6157     {
  6158       filename_to_ansi (filename, filename_a);
  6159       attrs = GetFileAttributesA (filename_a);
  6160     }
  6161   if (attrs == -1)
  6162     {
  6163       DWORD w32err = GetLastError ();
  6164 
  6165       switch (w32err)
  6166         {
  6167         case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
  6168           break;
  6169         case ERROR_ACCESS_DENIED:
  6170           errno = EACCES;
  6171           break;
  6172         case ERROR_FILE_NOT_FOUND:
  6173         case ERROR_PATH_NOT_FOUND:
  6174         default:
  6175           errno = ENOENT;
  6176           break;
  6177         }
  6178       return 0;
  6179     }
  6180   if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
  6181     return 0;
  6182   logon_network_drive (filename);
  6183   if (w32_unicode_filenames)
  6184     {
  6185       fh = FindFirstFileW (filename_w, &wfdw);
  6186       attrs_mean_symlink =
  6187         (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
  6188         && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
  6189       if (attrs_mean_symlink)
  6190         attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  6191     }
  6192   else if (_mbspbrk (filename_a, "?"))
  6193     {
  6194       /* filename_to_ansi failed to convert the file name.  */
  6195       errno = ENOENT;
  6196       return 0;
  6197     }
  6198   else
  6199     {
  6200       fh = FindFirstFileA (filename_a, &wfda);
  6201       attrs_mean_symlink =
  6202         (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
  6203         && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
  6204       if (attrs_mean_symlink)
  6205         attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  6206     }
  6207   if (fh == INVALID_HANDLE_VALUE)
  6208     return 0;
  6209   FindClose (fh);
  6210   return attrs_mean_symlink;
  6211 }
  6212 
  6213 /* If NAME identifies a symbolic link, copy into BUF the file name of
  6214    the symlink's target.  Copy at most BUF_SIZE bytes, and do NOT
  6215    null-terminate the target name, even if it fits.  Return the number
  6216    of bytes copied, or -1 if NAME is not a symlink or any error was
  6217    encountered while resolving it.  The file name copied into BUF is
  6218    encoded in the current ANSI codepage.  */
  6219 ssize_t
  6220 readlink (const char *name, char *buf, size_t buf_size)
  6221 {
  6222   const char *path;
  6223   TOKEN_PRIVILEGES privs;
  6224   int restore_privs = 0;
  6225   HANDLE sh;
  6226   ssize_t retval;
  6227   char resolved[MAX_UTF8_PATH];
  6228 
  6229   if (name == NULL)
  6230     {
  6231       errno = EFAULT;
  6232       return -1;
  6233     }
  6234   if (!*name)
  6235     {
  6236       errno = ENOENT;
  6237       return -1;
  6238     }
  6239 
  6240   path = map_w32_filename (name, NULL);
  6241 
  6242   if (strlen (path) > MAX_UTF8_PATH)
  6243     {
  6244       errno = ENAMETOOLONG;
  6245       return -1;
  6246     }
  6247 
  6248   errno = 0;
  6249   if (is_windows_9x () == TRUE
  6250       || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
  6251       || !is_symlink (path))
  6252     {
  6253       if (!errno)
  6254         errno = EINVAL; /* not a symlink */
  6255       return -1;
  6256     }
  6257 
  6258   /* Done with simple tests, now we're in for some _real_ work.  */
  6259   if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
  6260     restore_privs = 1;
  6261   /* Implementation note: From here and onward, don't return early,
  6262      since that will fail to restore the original set of privileges of
  6263      the calling thread.  */
  6264 
  6265   retval = -1;  /* not too optimistic, are we? */
  6266 
  6267   /* Note: In the next call to CreateFile, we use zero as the 2nd
  6268      argument because, when the symlink is a hidden/system file,
  6269      e.g. 'C:\Users\All Users', GENERIC_READ fails with
  6270      ERROR_ACCESS_DENIED.  Zero seems to work just fine, both for file
  6271      and directory symlinks.  */
  6272   if (w32_unicode_filenames)
  6273     {
  6274       wchar_t path_w[MAX_PATH];
  6275 
  6276       filename_to_utf16 (path, path_w);
  6277       sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
  6278                         FILE_FLAG_OPEN_REPARSE_POINT
  6279                         | FILE_FLAG_BACKUP_SEMANTICS,
  6280                         NULL);
  6281     }
  6282   else
  6283     {
  6284       char path_a[MAX_PATH];
  6285 
  6286       filename_to_ansi (path, path_a);
  6287       sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
  6288                         FILE_FLAG_OPEN_REPARSE_POINT
  6289                         | FILE_FLAG_BACKUP_SEMANTICS,
  6290                         NULL);
  6291     }
  6292   if (sh != INVALID_HANDLE_VALUE)
  6293     {
  6294       BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
  6295       REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
  6296       DWORD retbytes;
  6297 
  6298       if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
  6299                             reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
  6300                             &retbytes, NULL))
  6301         errno = EIO;
  6302       else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
  6303         errno = EINVAL;
  6304       else
  6305         {
  6306           /* Copy the link target name, in wide characters, from
  6307              reparse_data, then convert it to multibyte encoding in
  6308              the current locale's codepage.  */
  6309           WCHAR *lwname;
  6310           size_t lname_size;
  6311           USHORT lwname_len =
  6312             reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
  6313           WCHAR *lwname_src =
  6314             reparse_data->SymbolicLinkReparseBuffer.PathBuffer
  6315             + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
  6316           size_t size_to_copy = buf_size;
  6317 
  6318           /* According to MSDN, PrintNameLength does not include the
  6319              terminating null character.  */
  6320           lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
  6321           memcpy (lwname, lwname_src, lwname_len);
  6322           lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
  6323           filename_from_utf16 (lwname, resolved);
  6324           dostounix_filename (resolved);
  6325           lname_size = strlen (resolved) + 1;
  6326           if (lname_size <= buf_size)
  6327             size_to_copy = lname_size;
  6328           memcpy (buf, resolved, size_to_copy);
  6329           /* Success!  */
  6330           retval = size_to_copy;
  6331         }
  6332       CloseHandle (sh);
  6333     }
  6334   else
  6335     {
  6336       /* CreateFile failed.  */
  6337       DWORD w32err2 = GetLastError ();
  6338 
  6339       switch (w32err2)
  6340         {
  6341         case ERROR_FILE_NOT_FOUND:
  6342         case ERROR_PATH_NOT_FOUND:
  6343           errno = ENOENT;
  6344           break;
  6345         case ERROR_ACCESS_DENIED:
  6346         case ERROR_TOO_MANY_OPEN_FILES:
  6347           errno = EACCES;
  6348           break;
  6349         default:
  6350           errno = EPERM;
  6351           break;
  6352         }
  6353     }
  6354   if (restore_privs)
  6355     {
  6356       restore_privilege (&privs);
  6357       revert_to_self ();
  6358     }
  6359 
  6360   return retval;
  6361 }
  6362 
  6363 ssize_t
  6364 readlinkat (int fd, char const *name, char *buffer,
  6365             size_t buffer_size)
  6366 {
  6367   /* Rely on a hack: an open directory is modeled as file descriptor 0,
  6368      as in fstatat.  FIXME: Add proper support for readlinkat.  */
  6369   char fullname[MAX_UTF8_PATH];
  6370 
  6371   if (fd != AT_FDCWD)
  6372     {
  6373       if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
  6374           < 0)
  6375         {
  6376           errno = ENAMETOOLONG;
  6377           return -1;
  6378         }
  6379       name = fullname;
  6380     }
  6381 
  6382   return readlink (name, buffer, buffer_size);
  6383 }
  6384 
  6385 /* If FILE is a symlink, return its target (stored in a static
  6386    buffer); otherwise return FILE.
  6387 
  6388    This function repeatedly resolves symlinks in the last component of
  6389    a chain of symlink file names, as in foo -> bar -> baz -> ...,
  6390    until it arrives at a file whose last component is not a symlink,
  6391    or some error occurs.  It returns the target of the last
  6392    successfully resolved symlink in the chain.  If it succeeds to
  6393    resolve even a single symlink, the value returned is an absolute
  6394    file name with backslashes (result of GetFullPathName).  By
  6395    contrast, if the original FILE is returned, it is unaltered.
  6396 
  6397    Note: This function can set errno even if it succeeds.
  6398 
  6399    Implementation note: we only resolve the last portion ("basename")
  6400    of the argument FILE and of each following file in the chain,
  6401    disregarding any possible symlinks in its leading directories.
  6402    This is because Windows system calls and library functions
  6403    transparently resolve symlinks in leading directories and return
  6404    correct information, as long as the basename is not a symlink.  */
  6405 static char *
  6406 chase_symlinks (const char *file)
  6407 {
  6408   static char target[MAX_UTF8_PATH];
  6409   char link[MAX_UTF8_PATH];
  6410   wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
  6411   char target_a[MAX_PATH], link_a[MAX_PATH];
  6412   ssize_t res, link_len;
  6413   int loop_count = 0;
  6414 
  6415   if (is_windows_9x () == TRUE || !is_symlink (file))
  6416     return (char *)file;
  6417 
  6418   if (w32_unicode_filenames)
  6419     {
  6420       wchar_t file_w[MAX_PATH];
  6421 
  6422       filename_to_utf16 (file, file_w);
  6423       if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
  6424         return (char *)file;
  6425       filename_from_utf16 (link_w, link);
  6426     }
  6427   else
  6428     {
  6429       char file_a[MAX_PATH];
  6430 
  6431       filename_to_ansi (file, file_a);
  6432       if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
  6433         return (char *)file;
  6434       filename_from_ansi (link_a, link);
  6435     }
  6436   link_len = strlen (link);
  6437 
  6438   target[0] = '\0';
  6439   do {
  6440 
  6441     /* Remove trailing slashes, as we want to resolve the last
  6442        non-trivial part of the link name.  */
  6443     while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
  6444       link[link_len--] = '\0';
  6445 
  6446     res = readlink (link, target, MAX_UTF8_PATH);
  6447     if (res > 0)
  6448       {
  6449         target[res] = '\0';
  6450         if (!(IS_DEVICE_SEP (target[1])
  6451               || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
  6452           {
  6453             /* Target is relative.  Append it to the directory part of
  6454                the symlink, then copy the result back to target.  */
  6455             char *p = link + link_len;
  6456 
  6457             while (p > link && !IS_ANY_SEP (p[-1]))
  6458               p--;
  6459             strcpy (p, target);
  6460             strcpy (target, link);
  6461           }
  6462         /* Resolve any "." and ".." to get a fully-qualified file name
  6463            in link[] again. */
  6464         if (w32_unicode_filenames)
  6465           {
  6466             filename_to_utf16 (target, target_w);
  6467             link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
  6468             if (link_len > 0)
  6469               filename_from_utf16 (link_w, link);
  6470           }
  6471         else
  6472           {
  6473             filename_to_ansi (target, target_a);
  6474             link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
  6475             if (link_len > 0)
  6476               filename_from_ansi (link_a, link);
  6477           }
  6478         link_len = strlen (link);
  6479       }
  6480   } while (res > 0 && link_len > 0 && ++loop_count <= 100);
  6481 
  6482   if (loop_count > 100)
  6483     errno = ELOOP;
  6484 
  6485   if (target[0] == '\0') /* not a single call to readlink succeeded */
  6486     return (char *)file;
  6487   return target;
  6488 }
  6489 
  6490 /* Return non-zero if FILE's filesystem supports symlinks.  */
  6491 bool
  6492 symlinks_supported (const char *file)
  6493 {
  6494   if (is_windows_9x () != TRUE
  6495       && get_volume_info (file, NULL)
  6496       && (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
  6497     return true;
  6498   return false;
  6499 }
  6500 
  6501 
  6502 /* Posix ACL emulation.  */
  6503 
  6504 int
  6505 acl_valid (acl_t acl)
  6506 {
  6507   return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
  6508 }
  6509 
  6510 char * ATTRIBUTE_MALLOC
  6511 acl_to_text (acl_t acl, ssize_t *size)
  6512 {
  6513   LPTSTR str_acl;
  6514   SECURITY_INFORMATION flags =
  6515     OWNER_SECURITY_INFORMATION |
  6516     GROUP_SECURITY_INFORMATION |
  6517     DACL_SECURITY_INFORMATION;
  6518   char *retval = NULL;
  6519   ULONG local_size;
  6520   int e = errno;
  6521 
  6522   errno = 0;
  6523 
  6524   if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
  6525     {
  6526       errno = e;
  6527       /* We don't want to mix heaps, so we duplicate the string in our
  6528          heap and free the one allocated by the API.  */
  6529       retval = xstrdup (str_acl);
  6530       if (size)
  6531         *size = local_size;
  6532       LocalFree (str_acl);
  6533     }
  6534   else if (errno != ENOTSUP)
  6535     errno = EINVAL;
  6536 
  6537   return retval;
  6538 }
  6539 
  6540 acl_t
  6541 acl_from_text (const char *acl_str)
  6542 {
  6543   PSECURITY_DESCRIPTOR psd, retval = NULL;
  6544   ULONG sd_size;
  6545   int e = errno;
  6546 
  6547   errno = 0;
  6548 
  6549   if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
  6550     {
  6551       errno = e;
  6552       retval = xmalloc (sd_size);
  6553       memcpy (retval, psd, sd_size);
  6554       LocalFree (psd);
  6555     }
  6556   else if (errno != ENOTSUP)
  6557     errno = EINVAL;
  6558 
  6559   return retval;
  6560 }
  6561 
  6562 int
  6563 acl_free (void *ptr)
  6564 {
  6565   xfree (ptr);
  6566   return 0;
  6567 }
  6568 
  6569 acl_t
  6570 acl_get_file (const char *fname, acl_type_t type)
  6571 {
  6572   PSECURITY_DESCRIPTOR psd = NULL;
  6573   const char *filename;
  6574 
  6575   if (type == ACL_TYPE_ACCESS)
  6576     {
  6577       DWORD sd_len, err;
  6578       SECURITY_INFORMATION si =
  6579         OWNER_SECURITY_INFORMATION |
  6580         GROUP_SECURITY_INFORMATION |
  6581         DACL_SECURITY_INFORMATION ;
  6582       int e = errno;
  6583 
  6584       filename = map_w32_filename (fname, NULL);
  6585       if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
  6586         fname = chase_symlinks (filename);
  6587       else
  6588         fname = filename;
  6589 
  6590       errno = 0;
  6591       if (!get_file_security (fname, si, psd, 0, &sd_len)
  6592           && errno != ENOTSUP)
  6593         {
  6594           err = GetLastError ();
  6595           if (err == ERROR_INSUFFICIENT_BUFFER)
  6596             {
  6597               psd = xmalloc (sd_len);
  6598               if (!get_file_security (fname, si, psd, sd_len, &sd_len))
  6599                 {
  6600                   xfree (psd);
  6601                   err = GetLastError ();
  6602                   if (err == ERROR_NOT_SUPPORTED
  6603                       || err == ERROR_ACCESS_DENIED
  6604                       || err == ERROR_INVALID_FUNCTION)
  6605                     errno = ENOTSUP;
  6606                   else if (err == ERROR_FILE_NOT_FOUND
  6607                            || err == ERROR_PATH_NOT_FOUND
  6608                            || err == ERROR_INVALID_NAME)
  6609                     errno = ENOENT;
  6610                   else
  6611                     errno = EIO;
  6612                   psd = NULL;
  6613                 }
  6614             }
  6615           else if (err == ERROR_FILE_NOT_FOUND
  6616                    || err == ERROR_PATH_NOT_FOUND
  6617                    /* ERROR_INVALID_NAME is what we get if
  6618                       w32-unicode-filenames is nil and the file cannot
  6619                       be encoded in the current ANSI codepage. */
  6620                    || err == ERROR_INVALID_NAME)
  6621             errno = ENOENT;
  6622           else if (err == ERROR_NOT_SUPPORTED
  6623                    /* ERROR_ACCESS_DENIED or ERROR_INVALID_FUNCTION is
  6624                       what we get for a volume mounted by WebDAV,
  6625                       which evidently doesn't support ACLs.  */
  6626                    || err == ERROR_ACCESS_DENIED
  6627                    || err == ERROR_INVALID_FUNCTION)
  6628             errno = ENOTSUP;
  6629           else
  6630             errno = EIO;
  6631         }
  6632       else if (!errno)
  6633         errno = e;
  6634     }
  6635   else if (type != ACL_TYPE_DEFAULT)
  6636     errno = EINVAL;
  6637 
  6638   return psd;
  6639 }
  6640 
  6641 int
  6642 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
  6643 {
  6644   TOKEN_PRIVILEGES old1, old2;
  6645   DWORD err;
  6646   int st = 0, retval = -1;
  6647   SECURITY_INFORMATION flags = 0;
  6648   PSID psidOwner, psidGroup;
  6649   PACL pacl;
  6650   BOOL dflt;
  6651   BOOL dacl_present;
  6652   int e;
  6653   const char *filename;
  6654 
  6655   if (acl_valid (acl) != 0
  6656       || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
  6657     {
  6658       errno = EINVAL;
  6659       return -1;
  6660     }
  6661 
  6662   if (type == ACL_TYPE_DEFAULT)
  6663     {
  6664       errno = ENOSYS;
  6665       return -1;
  6666     }
  6667 
  6668   filename = map_w32_filename (fname, NULL);
  6669   if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
  6670     fname = chase_symlinks (filename);
  6671   else
  6672     fname = filename;
  6673 
  6674   if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
  6675                                      &dflt)
  6676       && psidOwner)
  6677     flags |= OWNER_SECURITY_INFORMATION;
  6678   if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
  6679                                      &dflt)
  6680       && psidGroup)
  6681     flags |= GROUP_SECURITY_INFORMATION;
  6682   if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
  6683                                     &pacl, &dflt)
  6684       && dacl_present)
  6685     flags |= DACL_SECURITY_INFORMATION;
  6686   if (!flags)
  6687     return 0;
  6688 
  6689   /* According to KB-245153, setting the owner will succeed if either:
  6690      (1) the caller is the user who will be the new owner, and has the
  6691          SE_TAKE_OWNERSHIP privilege, or
  6692      (2) the caller has the SE_RESTORE privilege, in which case she can
  6693          set any valid user or group as the owner
  6694 
  6695      We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
  6696      privileges, and disregard any failures in obtaining them.  If
  6697      these privileges cannot be obtained, and do not already exist in
  6698      the calling thread's security token, this function could fail
  6699      with EPERM.  */
  6700   if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
  6701     st++;
  6702   if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
  6703     st++;
  6704 
  6705   e = errno;
  6706   errno = 0;
  6707   /* SetFileSecurity is deprecated by MS, and sometimes fails when
  6708      DACL inheritance is involved, but it seems to preserve ownership
  6709      better than SetNamedSecurityInfo, which is important e.g., in
  6710      copy-file.  */
  6711   if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
  6712     {
  6713       err = GetLastError ();
  6714 
  6715       if (errno != ENOTSUP)
  6716         err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
  6717                                        psidOwner, psidGroup, pacl, NULL);
  6718     }
  6719   else
  6720     err = ERROR_SUCCESS;
  6721   if (err != ERROR_SUCCESS)
  6722     {
  6723       if (errno == ENOTSUP)
  6724         ;
  6725       else if (err == ERROR_INVALID_OWNER
  6726                || err == ERROR_NOT_ALL_ASSIGNED
  6727                || err == ERROR_ACCESS_DENIED)
  6728         {
  6729           /* Maybe the requested ACL and the one the file already has
  6730              are identical, in which case we can silently ignore the
  6731              failure.  (And no, Windows doesn't.)  */
  6732           acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
  6733 
  6734           errno = EPERM;
  6735           if (current_acl)
  6736             {
  6737               char *acl_from = acl_to_text (current_acl, NULL);
  6738               char *acl_to = acl_to_text (acl, NULL);
  6739 
  6740               if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
  6741                 {
  6742                   retval = 0;
  6743                   errno = e;
  6744                 }
  6745               if (acl_from)
  6746                 acl_free (acl_from);
  6747               if (acl_to)
  6748                 acl_free (acl_to);
  6749               acl_free (current_acl);
  6750             }
  6751         }
  6752       else if (err == ERROR_FILE_NOT_FOUND
  6753                || err == ERROR_PATH_NOT_FOUND
  6754                /* ERROR_INVALID_NAME is what we get if
  6755                   w32-unicode-filenames is nil and the file cannot be
  6756                   encoded in the current ANSI codepage. */
  6757                || err == ERROR_INVALID_NAME)
  6758         errno = ENOENT;
  6759       else
  6760         errno = EACCES;
  6761     }
  6762   else
  6763     {
  6764       retval = 0;
  6765       errno = e;
  6766     }
  6767 
  6768   if (st)
  6769     {
  6770       if (st >= 2)
  6771         restore_privilege (&old2);
  6772       restore_privilege (&old1);
  6773       revert_to_self ();
  6774     }
  6775 
  6776   return retval;
  6777 }
  6778 
  6779 /* Return true if errno value ERRNUM indicates that ACLs are well
  6780    supported on this system.  ERRNUM should be an errno value obtained
  6781    after an ACL-related system call fails.  */
  6782 bool
  6783 acl_errno_valid (int errnum)
  6784 {
  6785   switch (errnum)
  6786     {
  6787     case EBUSY:
  6788     case EINVAL:
  6789     case ENOTSUP:
  6790       return false;
  6791     default:
  6792       return true;
  6793     }
  6794 }
  6795 
  6796 
  6797 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c).  We
  6798    have a fixed max size for file names, so we don't need the kind of
  6799    alloc/malloc/realloc dance the gnulib version does.  We also don't
  6800    support FD-relative symlinks.  */
  6801 char *
  6802 careadlinkat (int fd, char const *filename,
  6803               char *buffer, size_t buffer_size,
  6804               struct allocator const *alloc,
  6805               ssize_t (*preadlinkat) (int, char const *, char *, size_t))
  6806 {
  6807   char linkname[MAX_UTF8_PATH];
  6808   ssize_t link_size;
  6809 
  6810   link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
  6811 
  6812   if (link_size > 0)
  6813     {
  6814       char *retval = buffer;
  6815 
  6816       linkname[link_size++] = '\0';
  6817       if (link_size > buffer_size)
  6818         retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
  6819       if (retval)
  6820         memcpy (retval, linkname, link_size);
  6821 
  6822       return retval;
  6823     }
  6824   return NULL;
  6825 }
  6826 
  6827 int
  6828 w32_copy_file (const char *from, const char *to,
  6829                int keep_time, int preserve_ownership, int copy_acls)
  6830 {
  6831   acl_t acl = NULL;
  6832   BOOL copy_result;
  6833   wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
  6834   char from_a[MAX_PATH], to_a[MAX_PATH];
  6835 
  6836   /* We ignore preserve_ownership for now.  */
  6837   preserve_ownership = preserve_ownership;
  6838 
  6839   if (copy_acls)
  6840     {
  6841       acl = acl_get_file (from, ACL_TYPE_ACCESS);
  6842       if (acl == NULL && acl_errno_valid (errno))
  6843         return -2;
  6844     }
  6845   if (w32_unicode_filenames)
  6846     {
  6847       filename_to_utf16 (from, from_w);
  6848       filename_to_utf16 (to, to_w);
  6849       copy_result = CopyFileW (from_w, to_w, FALSE);
  6850     }
  6851   else
  6852     {
  6853       filename_to_ansi (from, from_a);
  6854       filename_to_ansi (to, to_a);
  6855       copy_result = CopyFileA (from_a, to_a, FALSE);
  6856     }
  6857   if (!copy_result)
  6858     {
  6859       /* CopyFile doesn't set errno when it fails.  By far the most
  6860          "popular" reason is that the target is read-only.  */
  6861       DWORD err = GetLastError ();
  6862 
  6863       switch (err)
  6864         {
  6865         case ERROR_FILE_NOT_FOUND:
  6866           errno = ENOENT;
  6867           break;
  6868         case ERROR_ACCESS_DENIED:
  6869           errno = EACCES;
  6870           break;
  6871         case ERROR_ENCRYPTION_FAILED:
  6872           errno = EIO;
  6873           break;
  6874         default:
  6875           errno = EPERM;
  6876           break;
  6877         }
  6878 
  6879       if (acl)
  6880         acl_free (acl);
  6881       return -1;
  6882     }
  6883   /* CopyFile retains the timestamp by default.  However, see
  6884      "Community Additions" for CopyFile: it sounds like that is not
  6885      entirely true.  Testing on Windows XP confirms that modified time
  6886      is copied, but creation and last-access times are not.
  6887      FIXME?  */
  6888   else if (!keep_time)
  6889     {
  6890       struct timespec tnow[2];
  6891       DWORD attributes;
  6892 
  6893       tnow[0] = tnow[1] = current_timespec ();
  6894       if (w32_unicode_filenames)
  6895         {
  6896           /* Ensure file is writable while its times are set.  */
  6897           attributes = GetFileAttributesW (to_w);
  6898           SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
  6899           if (utimensat (AT_FDCWD, to, tnow, 0))
  6900             {
  6901               /* Restore original attributes.  */
  6902               SetFileAttributesW (to_w, attributes);
  6903               if (acl)
  6904                 acl_free (acl);
  6905               return -3;
  6906             }
  6907           /* Restore original attributes.  */
  6908           SetFileAttributesW (to_w, attributes);
  6909         }
  6910       else
  6911         {
  6912           attributes = GetFileAttributesA (to_a);
  6913           SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
  6914           if (utimensat (AT_FDCWD, to, tnow, 0))
  6915             {
  6916               SetFileAttributesA (to_a, attributes);
  6917               if (acl)
  6918                 acl_free (acl);
  6919               return -3;
  6920             }
  6921           SetFileAttributesA (to_a, attributes);
  6922         }
  6923     }
  6924   if (acl != NULL)
  6925     {
  6926       bool fail =
  6927         acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
  6928       acl_free (acl);
  6929       if (fail && acl_errno_valid (errno))
  6930         return -4;
  6931     }
  6932 
  6933   return 0;
  6934 }
  6935 
  6936 
  6937 /* Support for browsing other processes and their attributes.  See
  6938    process.c for the Lisp bindings.  */
  6939 
  6940 /* Helper wrapper functions.  */
  6941 
  6942 static HANDLE WINAPI
  6943 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
  6944 {
  6945   static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
  6946 
  6947   if (g_b_init_create_toolhelp32_snapshot == 0)
  6948     {
  6949       g_b_init_create_toolhelp32_snapshot = 1;
  6950       s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
  6951         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  6952                               "CreateToolhelp32Snapshot");
  6953     }
  6954   if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
  6955     {
  6956       return INVALID_HANDLE_VALUE;
  6957     }
  6958   return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
  6959 }
  6960 
  6961 static BOOL WINAPI
  6962 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
  6963 {
  6964   static Process32First_Proc s_pfn_Process32_First = NULL;
  6965 
  6966   if (g_b_init_process32_first == 0)
  6967     {
  6968       g_b_init_process32_first = 1;
  6969       s_pfn_Process32_First = (Process32First_Proc)
  6970         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  6971                               "Process32First");
  6972     }
  6973   if (s_pfn_Process32_First == NULL)
  6974     {
  6975       return FALSE;
  6976     }
  6977   return (s_pfn_Process32_First (hSnapshot, lppe));
  6978 }
  6979 
  6980 static BOOL WINAPI
  6981 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
  6982 {
  6983   static Process32Next_Proc s_pfn_Process32_Next = NULL;
  6984 
  6985   if (g_b_init_process32_next == 0)
  6986     {
  6987       g_b_init_process32_next = 1;
  6988       s_pfn_Process32_Next = (Process32Next_Proc)
  6989         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  6990                               "Process32Next");
  6991     }
  6992   if (s_pfn_Process32_Next == NULL)
  6993     {
  6994       return FALSE;
  6995     }
  6996   return (s_pfn_Process32_Next (hSnapshot, lppe));
  6997 }
  6998 
  6999 static BOOL WINAPI
  7000 open_thread_token (HANDLE ThreadHandle,
  7001                    DWORD DesiredAccess,
  7002                    BOOL OpenAsSelf,
  7003                    PHANDLE TokenHandle)
  7004 {
  7005   static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
  7006   HMODULE hm_advapi32 = NULL;
  7007   if (is_windows_9x () == TRUE)
  7008     {
  7009       SetLastError (ERROR_NOT_SUPPORTED);
  7010       return FALSE;
  7011     }
  7012   if (g_b_init_open_thread_token == 0)
  7013     {
  7014       g_b_init_open_thread_token = 1;
  7015       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  7016       s_pfn_Open_Thread_Token = (OpenThreadToken_Proc)
  7017         get_proc_addr (hm_advapi32, "OpenThreadToken");
  7018     }
  7019   if (s_pfn_Open_Thread_Token == NULL)
  7020     {
  7021       SetLastError (ERROR_NOT_SUPPORTED);
  7022       return FALSE;
  7023     }
  7024   return (
  7025       s_pfn_Open_Thread_Token (
  7026           ThreadHandle,
  7027           DesiredAccess,
  7028           OpenAsSelf,
  7029           TokenHandle)
  7030       );
  7031 }
  7032 
  7033 static BOOL WINAPI
  7034 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
  7035 {
  7036   static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
  7037   HMODULE hm_advapi32 = NULL;
  7038   if (is_windows_9x () == TRUE)
  7039     {
  7040       return FALSE;
  7041     }
  7042   if (g_b_init_impersonate_self == 0)
  7043     {
  7044       g_b_init_impersonate_self = 1;
  7045       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  7046       s_pfn_Impersonate_Self = (ImpersonateSelf_Proc)
  7047         get_proc_addr (hm_advapi32, "ImpersonateSelf");
  7048     }
  7049   if (s_pfn_Impersonate_Self == NULL)
  7050     {
  7051       return FALSE;
  7052     }
  7053   return s_pfn_Impersonate_Self (ImpersonationLevel);
  7054 }
  7055 
  7056 static BOOL WINAPI
  7057 revert_to_self (void)
  7058 {
  7059   static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
  7060   HMODULE hm_advapi32 = NULL;
  7061   if (is_windows_9x () == TRUE)
  7062     {
  7063       return FALSE;
  7064     }
  7065   if (g_b_init_revert_to_self == 0)
  7066     {
  7067       g_b_init_revert_to_self = 1;
  7068       hm_advapi32 = LoadLibrary ("Advapi32.dll");
  7069       s_pfn_Revert_To_Self = (RevertToSelf_Proc)
  7070         get_proc_addr (hm_advapi32, "RevertToSelf");
  7071     }
  7072   if (s_pfn_Revert_To_Self == NULL)
  7073     {
  7074       return FALSE;
  7075     }
  7076   return s_pfn_Revert_To_Self ();
  7077 }
  7078 
  7079 static BOOL WINAPI
  7080 get_process_memory_info (HANDLE h_proc,
  7081                          PPROCESS_MEMORY_COUNTERS mem_counters,
  7082                          DWORD bufsize)
  7083 {
  7084   static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
  7085   HMODULE hm_psapi = NULL;
  7086   if (is_windows_9x () == TRUE)
  7087     {
  7088       return FALSE;
  7089     }
  7090   if (g_b_init_get_process_memory_info == 0)
  7091     {
  7092       g_b_init_get_process_memory_info = 1;
  7093       hm_psapi = LoadLibrary ("Psapi.dll");
  7094       if (hm_psapi)
  7095         s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
  7096           get_proc_addr (hm_psapi, "GetProcessMemoryInfo");
  7097     }
  7098   if (s_pfn_Get_Process_Memory_Info == NULL)
  7099     {
  7100       return FALSE;
  7101     }
  7102   return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
  7103 }
  7104 
  7105 static BOOL WINAPI
  7106 get_process_working_set_size (HANDLE h_proc,
  7107                               PSIZE_T minrss,
  7108                               PSIZE_T maxrss)
  7109 {
  7110   static GetProcessWorkingSetSize_Proc
  7111     s_pfn_Get_Process_Working_Set_Size = NULL;
  7112 
  7113   if (is_windows_9x () == TRUE)
  7114     {
  7115       return FALSE;
  7116     }
  7117   if (g_b_init_get_process_working_set_size == 0)
  7118     {
  7119       g_b_init_get_process_working_set_size = 1;
  7120       s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
  7121         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  7122                               "GetProcessWorkingSetSize");
  7123     }
  7124   if (s_pfn_Get_Process_Working_Set_Size == NULL)
  7125     {
  7126       return FALSE;
  7127     }
  7128   return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
  7129 }
  7130 
  7131 static BOOL WINAPI
  7132 global_memory_status (MEMORYSTATUS *buf)
  7133 {
  7134   static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
  7135 
  7136   if (is_windows_9x () == TRUE)
  7137     {
  7138       return FALSE;
  7139     }
  7140   if (g_b_init_global_memory_status == 0)
  7141     {
  7142       g_b_init_global_memory_status = 1;
  7143       s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
  7144         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  7145                               "GlobalMemoryStatus");
  7146     }
  7147   if (s_pfn_Global_Memory_Status == NULL)
  7148     {
  7149       return FALSE;
  7150     }
  7151   return s_pfn_Global_Memory_Status (buf);
  7152 }
  7153 
  7154 static BOOL WINAPI
  7155 global_memory_status_ex (MEMORY_STATUS_EX *buf)
  7156 {
  7157   static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
  7158 
  7159   if (is_windows_9x () == TRUE)
  7160     {
  7161       return FALSE;
  7162     }
  7163   if (g_b_init_global_memory_status_ex == 0)
  7164     {
  7165       g_b_init_global_memory_status_ex = 1;
  7166       s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
  7167         get_proc_addr (GetModuleHandle ("kernel32.dll"),
  7168                               "GlobalMemoryStatusEx");
  7169     }
  7170   if (s_pfn_Global_Memory_Status_Ex == NULL)
  7171     {
  7172       return FALSE;
  7173     }
  7174   return s_pfn_Global_Memory_Status_Ex (buf);
  7175 }
  7176 
  7177 Lisp_Object
  7178 list_system_processes (void)
  7179 {
  7180   Lisp_Object proclist = Qnil;
  7181   HANDLE h_snapshot;
  7182 
  7183   h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
  7184 
  7185   if (h_snapshot != INVALID_HANDLE_VALUE)
  7186     {
  7187       PROCESSENTRY32 proc_entry;
  7188       DWORD proc_id;
  7189       BOOL res;
  7190 
  7191       proc_entry.dwSize = sizeof (PROCESSENTRY32);
  7192       for (res = process32_first (h_snapshot, &proc_entry); res;
  7193            res = process32_next  (h_snapshot, &proc_entry))
  7194         {
  7195           proc_id = proc_entry.th32ProcessID;
  7196           proclist = Fcons (INT_TO_INTEGER (proc_id), proclist);
  7197         }
  7198 
  7199       CloseHandle (h_snapshot);
  7200       proclist = Fnreverse (proclist);
  7201     }
  7202 
  7203   return proclist;
  7204 }
  7205 
  7206 static int
  7207 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
  7208 {
  7209   TOKEN_PRIVILEGES priv;
  7210   DWORD priv_size = sizeof (priv);
  7211   DWORD opriv_size = sizeof (*old_priv);
  7212   HANDLE h_token = NULL;
  7213   HANDLE h_thread = GetCurrentThread ();
  7214   int ret_val = 0;
  7215   BOOL res;
  7216 
  7217   res = open_thread_token (h_thread,
  7218                            TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  7219                            FALSE, &h_token);
  7220   if (!res && GetLastError () == ERROR_NO_TOKEN)
  7221     {
  7222       if (impersonate_self (SecurityImpersonation))
  7223           res = open_thread_token (h_thread,
  7224                                    TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  7225                                    FALSE, &h_token);
  7226     }
  7227   if (res)
  7228     {
  7229       priv.PrivilegeCount = 1;
  7230       priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
  7231       LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
  7232       if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
  7233                                  old_priv, &opriv_size)
  7234           && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
  7235         ret_val = 1;
  7236     }
  7237   if (h_token)
  7238     CloseHandle (h_token);
  7239 
  7240   return ret_val;
  7241 }
  7242 
  7243 static int
  7244 restore_privilege (TOKEN_PRIVILEGES *priv)
  7245 {
  7246   DWORD priv_size = sizeof (*priv);
  7247   HANDLE h_token = NULL;
  7248   int ret_val = 0;
  7249 
  7250   if (open_thread_token (GetCurrentThread (),
  7251                          TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  7252                          FALSE, &h_token))
  7253     {
  7254       if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
  7255           && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
  7256         ret_val = 1;
  7257     }
  7258   if (h_token)
  7259     CloseHandle (h_token);
  7260 
  7261   return ret_val;
  7262 }
  7263 
  7264 static Lisp_Object
  7265 ltime (ULONGLONG time_100ns)
  7266 {
  7267   ULONGLONG time_sec = time_100ns / 10000000;
  7268   int subsec = time_100ns % 10000000;
  7269   return list4i (time_sec >> 16, time_sec & 0xffff,
  7270                  subsec / 10, subsec % 10 * 100000);
  7271 }
  7272 
  7273 #define U64_TO_LISP_TIME(time) ltime (time)
  7274 
  7275 static int
  7276 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
  7277                Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
  7278                double *pcpu)
  7279 {
  7280   FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
  7281   ULONGLONG tem1, tem2, tem3, tem;
  7282 
  7283   if (!h_proc
  7284       || !get_process_times_fn
  7285       || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
  7286                                    &ft_kernel, &ft_user))
  7287     return 0;
  7288 
  7289   GetSystemTimeAsFileTime (&ft_current);
  7290 
  7291   FILETIME_TO_U64 (tem1, ft_kernel);
  7292   *stime = U64_TO_LISP_TIME (tem1);
  7293 
  7294   FILETIME_TO_U64 (tem2, ft_user);
  7295   *utime = U64_TO_LISP_TIME (tem2);
  7296 
  7297   tem3 = tem1 + tem2;
  7298   *ttime = U64_TO_LISP_TIME (tem3);
  7299 
  7300   FILETIME_TO_U64 (tem, ft_creation);
  7301   /* Process no 4 (System) returns zero creation time.  */
  7302   if (tem)
  7303     tem -= utc_base;
  7304   *ctime = U64_TO_LISP_TIME (tem);
  7305 
  7306   if (tem)
  7307     {
  7308       FILETIME_TO_U64 (tem3, ft_current);
  7309       tem = (tem3 - utc_base) - tem;
  7310     }
  7311   *etime = U64_TO_LISP_TIME (tem);
  7312 
  7313   if (tem)
  7314     {
  7315       *pcpu = 100.0 * (tem1 + tem2) / tem;
  7316       if (*pcpu > 100)
  7317         *pcpu = 100.0;
  7318     }
  7319   else
  7320     *pcpu = 0;
  7321 
  7322   return 1;
  7323 }
  7324 
  7325 Lisp_Object
  7326 system_process_attributes (Lisp_Object pid)
  7327 {
  7328   Lisp_Object attrs = Qnil;
  7329   Lisp_Object cmd_str, decoded_cmd, tem;
  7330   HANDLE h_snapshot, h_proc;
  7331   DWORD proc_id;
  7332   int found_proc = 0;
  7333   char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
  7334   DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
  7335   DWORD glength = sizeof (gname);
  7336   HANDLE token = NULL;
  7337   SID_NAME_USE user_type;
  7338   unsigned char *buf = NULL;
  7339   DWORD blen = 0;
  7340   TOKEN_USER user_token;
  7341   TOKEN_PRIMARY_GROUP group_token;
  7342   unsigned euid;
  7343   unsigned egid;
  7344   PROCESS_MEMORY_COUNTERS mem;
  7345   PROCESS_MEMORY_COUNTERS_EX mem_ex;
  7346   SIZE_T minrss, maxrss;
  7347   MEMORYSTATUS memst;
  7348   MEMORY_STATUS_EX memstex;
  7349   double totphys = 0.0;
  7350   Lisp_Object ctime, stime, utime, etime, ttime;
  7351   double pcpu;
  7352   BOOL result = FALSE;
  7353 
  7354   CHECK_NUMBER (pid);
  7355   proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XFIXNUM (pid);
  7356 
  7357   h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
  7358 
  7359   if (h_snapshot != INVALID_HANDLE_VALUE)
  7360     {
  7361       PROCESSENTRY32 pe;
  7362       BOOL res;
  7363 
  7364       pe.dwSize = sizeof (PROCESSENTRY32);
  7365       for (res = process32_first (h_snapshot, &pe); res;
  7366            res = process32_next  (h_snapshot, &pe))
  7367         {
  7368           if (proc_id == pe.th32ProcessID)
  7369             {
  7370               if (proc_id == 0)
  7371                 decoded_cmd = build_string ("Idle");
  7372               else
  7373                 {
  7374                   /* Decode the command name from locale-specific
  7375                      encoding.  */
  7376                   cmd_str = build_unibyte_string (pe.szExeFile);
  7377 
  7378                   decoded_cmd =
  7379                     code_convert_string_norecord (cmd_str,
  7380                                                   Vlocale_coding_system, 0);
  7381                 }
  7382               attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
  7383               attrs = Fcons (Fcons (Qppid,
  7384                                     INT_TO_INTEGER (pe.th32ParentProcessID)),
  7385                              attrs);
  7386               attrs = Fcons (Fcons (Qpri, make_fixnum (pe.pcPriClassBase)),
  7387                              attrs);
  7388               attrs = Fcons (Fcons (Qthcount,
  7389                                     INT_TO_INTEGER (pe.cntThreads)),
  7390                              attrs);
  7391               found_proc = 1;
  7392               break;
  7393             }
  7394         }
  7395 
  7396       CloseHandle (h_snapshot);
  7397     }
  7398 
  7399   if (!found_proc)
  7400     return Qnil;
  7401 
  7402   h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  7403                         FALSE, proc_id);
  7404   /* If we were denied a handle to the process, try again after
  7405      enabling the SeDebugPrivilege in our process.  */
  7406   if (!h_proc)
  7407     {
  7408       TOKEN_PRIVILEGES priv_current;
  7409 
  7410       if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
  7411         {
  7412           h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
  7413                                 FALSE, proc_id);
  7414           restore_privilege (&priv_current);
  7415           revert_to_self ();
  7416         }
  7417     }
  7418   if (h_proc)
  7419     {
  7420       result = open_process_token (h_proc, TOKEN_QUERY, &token);
  7421       if (result)
  7422         {
  7423           result = get_token_information (token, TokenUser, NULL, 0, &blen);
  7424           if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
  7425             {
  7426               buf = xmalloc (blen);
  7427               result = get_token_information (token, TokenUser,
  7428                                               (LPVOID)buf, blen, &needed);
  7429               if (result)
  7430                 {
  7431                   memcpy (&user_token, buf, sizeof (user_token));
  7432                   if (!w32_cached_id (user_token.User.Sid, &euid, uname))
  7433                     {
  7434                       euid = get_rid (user_token.User.Sid);
  7435                       result = lookup_account_sid (NULL, user_token.User.Sid,
  7436                                                    uname, &ulength,
  7437                                                    domain, &dlength,
  7438                                                    &user_type);
  7439                       if (result)
  7440                         w32_add_to_cache (user_token.User.Sid, euid, uname);
  7441                       else
  7442                         {
  7443                           strcpy (uname, "unknown");
  7444                           result = TRUE;
  7445                         }
  7446                     }
  7447                   ulength = strlen (uname);
  7448                 }
  7449             }
  7450         }
  7451       if (result)
  7452         {
  7453           /* Determine a reasonable euid and gid values.  */
  7454           if (xstrcasecmp ("administrator", uname) == 0)
  7455             {
  7456               euid = 500;       /* well-known Administrator uid */
  7457               egid = 513;       /* well-known None gid */
  7458             }
  7459           else
  7460             {
  7461               /* Get group id and name.  */
  7462               result = get_token_information (token, TokenPrimaryGroup,
  7463                                               (LPVOID)buf, blen, &needed);
  7464               if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
  7465                 {
  7466                   buf = xrealloc (buf, blen = needed);
  7467                   result = get_token_information (token, TokenPrimaryGroup,
  7468                                                   (LPVOID)buf, blen, &needed);
  7469                 }
  7470               if (result)
  7471                 {
  7472                   memcpy (&group_token, buf, sizeof (group_token));
  7473                   if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
  7474                     {
  7475                       egid = get_rid (group_token.PrimaryGroup);
  7476                       dlength = sizeof (domain);
  7477                       result =
  7478                         lookup_account_sid (NULL, group_token.PrimaryGroup,
  7479                                             gname, &glength, NULL, &dlength,
  7480                                             &user_type);
  7481                       if (result)
  7482                         w32_add_to_cache (group_token.PrimaryGroup,
  7483                                           egid, gname);
  7484                       else
  7485                         {
  7486                           strcpy (gname, "None");
  7487                           result = TRUE;
  7488                         }
  7489                     }
  7490                   glength = strlen (gname);
  7491                 }
  7492             }
  7493         }
  7494       xfree (buf);
  7495     }
  7496   if (!result)
  7497     {
  7498       if (!is_windows_9x ())
  7499         {
  7500           /* We couldn't open the process token, presumably because of
  7501              insufficient access rights.  Assume this process is run
  7502              by the system.  */
  7503           strcpy (uname, "SYSTEM");
  7504           strcpy (gname, "None");
  7505           euid = 18;    /* SYSTEM */
  7506           egid = 513;   /* None */
  7507           glength = strlen (gname);
  7508           ulength = strlen (uname);
  7509         }
  7510       /* If we are running under Windows 9X, where security calls are
  7511          not supported, we assume all processes are run by the current
  7512          user.  */
  7513       else if (GetUserName (uname, &ulength))
  7514         {
  7515           if (xstrcasecmp ("administrator", uname) == 0)
  7516             euid = 0;
  7517           else
  7518             euid = 123;
  7519           egid = euid;
  7520           strcpy (gname, "None");
  7521           glength = strlen (gname);
  7522           ulength = strlen (uname);
  7523         }
  7524       else
  7525         {
  7526           euid = 123;
  7527           egid = 123;
  7528           strcpy (uname, "administrator");
  7529           ulength = strlen (uname);
  7530           strcpy (gname, "None");
  7531           glength = strlen (gname);
  7532         }
  7533       if (token)
  7534         CloseHandle (token);
  7535     }
  7536 
  7537   attrs = Fcons (Fcons (Qeuid, INT_TO_INTEGER (euid)), attrs);
  7538   tem = make_unibyte_string (uname, ulength);
  7539   attrs = Fcons (Fcons (Quser,
  7540                          code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
  7541                  attrs);
  7542   attrs = Fcons (Fcons (Qegid, INT_TO_INTEGER (egid)), attrs);
  7543   tem = make_unibyte_string (gname, glength);
  7544   attrs = Fcons (Fcons (Qgroup,
  7545                          code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
  7546                  attrs);
  7547 
  7548   memstex.dwLength = sizeof (memstex);
  7549   if (global_memory_status_ex (&memstex))
  7550 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
  7551     totphys = memstex.ullTotalPhys / 1024.0;
  7552 #else
  7553   /* Visual Studio 6 cannot convert an unsigned __int64 type to
  7554      double, so we need to do this for it...  */
  7555     {
  7556       DWORD tot_hi = memstex.ullTotalPhys >> 32;
  7557       DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
  7558       DWORD tot_lo = memstex.ullTotalPhys % 1024;
  7559 
  7560       totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
  7561     }
  7562 #endif  /* __GNUC__ || _MSC_VER >= 1300 */
  7563   else if (global_memory_status (&memst))
  7564     totphys = memst.dwTotalPhys / 1024.0;
  7565 
  7566   if (h_proc
  7567       && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
  7568                                   sizeof (mem_ex)))
  7569     {
  7570       SIZE_T rss = mem_ex.WorkingSetSize / 1024;
  7571 
  7572       attrs = Fcons (Fcons (Qmajflt,
  7573                             INT_TO_INTEGER (mem_ex.PageFaultCount)),
  7574                      attrs);
  7575       attrs = Fcons (Fcons (Qvsize,
  7576                             INT_TO_INTEGER (mem_ex.PrivateUsage / 1024)),
  7577                      attrs);
  7578       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (rss)), attrs);
  7579       if (totphys)
  7580         attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
  7581     }
  7582   else if (h_proc
  7583            && get_process_memory_info (h_proc, &mem, sizeof (mem)))
  7584     {
  7585       SIZE_T rss = mem_ex.WorkingSetSize / 1024;
  7586 
  7587       attrs = Fcons (Fcons (Qmajflt,
  7588                             INT_TO_INTEGER (mem.PageFaultCount)),
  7589                      attrs);
  7590       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (rss)), attrs);
  7591       if (totphys)
  7592         attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
  7593     }
  7594   else if (h_proc
  7595            && get_process_working_set_size (h_proc, &minrss, &maxrss))
  7596     {
  7597       DWORD rss = maxrss / 1024;
  7598 
  7599       attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (maxrss / 1024)), attrs);
  7600       if (totphys)
  7601         attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
  7602     }
  7603 
  7604   if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
  7605     {
  7606       attrs = Fcons (Fcons (Qutime, utime), attrs);
  7607       attrs = Fcons (Fcons (Qstime, stime), attrs);
  7608       attrs = Fcons (Fcons (Qtime,  ttime), attrs);
  7609       attrs = Fcons (Fcons (Qstart, ctime), attrs);
  7610       attrs = Fcons (Fcons (Qetime, etime), attrs);
  7611       attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
  7612     }
  7613 
  7614   /* FIXME: Retrieve command line by walking the PEB of the process.  */
  7615 
  7616   if (h_proc)
  7617     CloseHandle (h_proc);
  7618   return attrs;
  7619 }
  7620 
  7621 int
  7622 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
  7623                  unsigned long long *totalswap, unsigned long long *freeswap)
  7624 {
  7625   MEMORYSTATUS memst;
  7626   MEMORY_STATUS_EX memstex;
  7627 
  7628   /* Use GlobalMemoryStatusEx if available, as it can report more than
  7629      2GB of memory.  */
  7630   if (global_memory_status_ex (&memstex))
  7631     {
  7632       *totalram  = memstex.ullTotalPhys;
  7633       *freeram   = memstex.ullAvailPhys;
  7634       *totalswap = memstex.ullTotalPageFile;
  7635       *freeswap  = memstex.ullAvailPageFile;
  7636       return 0;
  7637     }
  7638   else if (global_memory_status (&memst))
  7639     {
  7640       *totalram = memst.dwTotalPhys;
  7641       *freeram   = memst.dwAvailPhys;
  7642       *totalswap = memst.dwTotalPageFile;
  7643       *freeswap  = memst.dwAvailPageFile;
  7644       return 0;
  7645     }
  7646   else
  7647     return -1;
  7648 }
  7649 
  7650 
  7651 /* Wrappers for  winsock functions to map between our file descriptors
  7652    and winsock's handles; also set h_errno for convenience.
  7653 
  7654    To allow Emacs to run on systems which don't have winsock support
  7655    installed, we dynamically link to winsock on startup if present, and
  7656    otherwise provide the minimum necessary functionality
  7657    (eg. gethostname). */
  7658 
  7659 /* function pointers for relevant socket functions */
  7660 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
  7661 void (PASCAL *pfn_WSASetLastError) (int iError);
  7662 int (PASCAL *pfn_WSAGetLastError) (void);
  7663 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
  7664 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
  7665                                         WSANETWORKEVENTS *NetworkEvents);
  7666 
  7667 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
  7668 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
  7669 int (PASCAL *pfn_socket) (int af, int type, int protocol);
  7670 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
  7671 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
  7672 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
  7673 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
  7674 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
  7675 int (PASCAL *pfn_closesocket) (SOCKET s);
  7676 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
  7677 int (PASCAL *pfn_WSACleanup) (void);
  7678 
  7679 u_short (PASCAL *pfn_htons) (u_short hostshort);
  7680 u_short (PASCAL *pfn_ntohs) (u_short netshort);
  7681 u_long (PASCAL *pfn_htonl) (u_long hostlong);
  7682 u_long (PASCAL *pfn_ntohl) (u_long netlong);
  7683 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
  7684 int (PASCAL *pfn_gethostname) (char * name, int namelen);
  7685 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
  7686 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
  7687 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
  7688 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
  7689                               const char * optval, int optlen);
  7690 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
  7691 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
  7692                                int * namelen);
  7693 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
  7694 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
  7695                        struct sockaddr * from, int * fromlen);
  7696 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
  7697                           const struct sockaddr * to, int tolen);
  7698 
  7699 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
  7700                                const struct addrinfo *, struct addrinfo **);
  7701 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
  7702 
  7703 /* SetHandleInformation is only needed to make sockets non-inheritable. */
  7704 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
  7705 #ifndef HANDLE_FLAG_INHERIT
  7706 #define HANDLE_FLAG_INHERIT     1
  7707 #endif
  7708 
  7709 HANDLE winsock_lib;
  7710 static int winsock_inuse;
  7711 
  7712 BOOL term_winsock (void);
  7713 
  7714 BOOL
  7715 term_winsock (void)
  7716 {
  7717   if (winsock_lib != NULL && winsock_inuse == 0)
  7718     {
  7719       release_listen_threads ();
  7720       /* Not sure what would cause WSAENETDOWN, or even if it can happen
  7721          after WSAStartup returns successfully, but it seems reasonable
  7722          to allow unloading winsock anyway in that case. */
  7723       if (pfn_WSACleanup () == 0 ||
  7724           pfn_WSAGetLastError () == WSAENETDOWN)
  7725         {
  7726           if (FreeLibrary (winsock_lib))
  7727           winsock_lib = NULL;
  7728           return TRUE;
  7729         }
  7730     }
  7731   return FALSE;
  7732 }
  7733 
  7734 BOOL
  7735 init_winsock (int load_now)
  7736 {
  7737   WSADATA  winsockData;
  7738 
  7739   if (winsock_lib != NULL)
  7740     return TRUE;
  7741 
  7742   pfn_SetHandleInformation
  7743     = (void *) get_proc_addr (GetModuleHandle ("kernel32.dll"),
  7744                                      "SetHandleInformation");
  7745 
  7746   winsock_lib = LoadLibrary ("Ws2_32.dll");
  7747 
  7748   if (winsock_lib != NULL)
  7749     {
  7750       /* dynamically link to socket functions */
  7751 
  7752 #define LOAD_PROC(fn) \
  7753       if ((pfn_##fn = (void *) get_proc_addr (winsock_lib, #fn)) == NULL) \
  7754         goto fail;
  7755 
  7756       LOAD_PROC (WSAStartup);
  7757       LOAD_PROC (WSASetLastError);
  7758       LOAD_PROC (WSAGetLastError);
  7759       LOAD_PROC (WSAEventSelect);
  7760       LOAD_PROC (WSAEnumNetworkEvents);
  7761       LOAD_PROC (WSACreateEvent);
  7762       LOAD_PROC (WSACloseEvent);
  7763       LOAD_PROC (socket);
  7764       LOAD_PROC (bind);
  7765       LOAD_PROC (connect);
  7766       LOAD_PROC (ioctlsocket);
  7767       LOAD_PROC (recv);
  7768       LOAD_PROC (send);
  7769       LOAD_PROC (closesocket);
  7770       LOAD_PROC (shutdown);
  7771       LOAD_PROC (htons);
  7772       LOAD_PROC (ntohs);
  7773       LOAD_PROC (htonl);
  7774       LOAD_PROC (ntohl);
  7775       LOAD_PROC (inet_addr);
  7776       LOAD_PROC (gethostname);
  7777       LOAD_PROC (gethostbyname);
  7778       LOAD_PROC (getservbyname);
  7779       LOAD_PROC (getpeername);
  7780       LOAD_PROC (WSACleanup);
  7781       LOAD_PROC (setsockopt);
  7782       LOAD_PROC (listen);
  7783       LOAD_PROC (getsockname);
  7784       LOAD_PROC (accept);
  7785       LOAD_PROC (recvfrom);
  7786       LOAD_PROC (sendto);
  7787 #undef LOAD_PROC
  7788 
  7789       /* Try loading functions not available before XP.  */
  7790       pfn_getaddrinfo = (void *) get_proc_addr (winsock_lib, "getaddrinfo");
  7791       pfn_freeaddrinfo = (void *) get_proc_addr (winsock_lib, "freeaddrinfo");
  7792       /* Paranoia: these two functions should go together, so if one
  7793          is absent, we cannot use the other.  */
  7794       if (pfn_getaddrinfo == NULL)
  7795         pfn_freeaddrinfo = NULL;
  7796       else if (pfn_freeaddrinfo == NULL)
  7797         pfn_getaddrinfo = NULL;
  7798 
  7799       /* specify version 1.1 of winsock */
  7800       if (pfn_WSAStartup (0x101, &winsockData) == 0)
  7801         {
  7802           if (winsockData.wVersion != 0x101)
  7803             goto fail;
  7804 
  7805           if (!load_now)
  7806             {
  7807               /* Report that winsock exists and is usable, but leave
  7808                  socket functions disabled.  I am assuming that calling
  7809                  WSAStartup does not require any network interaction,
  7810                  and in particular does not cause or require a dial-up
  7811                  connection to be established. */
  7812 
  7813               pfn_WSACleanup ();
  7814               FreeLibrary (winsock_lib);
  7815               winsock_lib = NULL;
  7816             }
  7817           winsock_inuse = 0;
  7818           return TRUE;
  7819         }
  7820 
  7821     fail:
  7822       FreeLibrary (winsock_lib);
  7823       winsock_lib = NULL;
  7824     }
  7825 
  7826   return FALSE;
  7827 }
  7828 
  7829 
  7830 int h_errno = 0;
  7831 
  7832 /* Function to map winsock error codes to errno codes for those errno
  7833    code defined in errno.h (errno values not defined by errno.h are
  7834    already in nt/inc/sys/socket.h).  */
  7835 static void
  7836 set_errno (void)
  7837 {
  7838   int wsa_err;
  7839 
  7840   h_errno = 0;
  7841   if (winsock_lib == NULL)
  7842     wsa_err = EINVAL;
  7843   else
  7844     wsa_err = pfn_WSAGetLastError ();
  7845 
  7846   switch (wsa_err)
  7847     {
  7848     case WSAEACCES:             errno = EACCES; break;
  7849     case WSAEBADF:              errno = EBADF; break;
  7850     case WSAEFAULT:             errno = EFAULT; break;
  7851     case WSAEINTR:              errno = EINTR; break;
  7852     case WSAEINVAL:             errno = EINVAL; break;
  7853     case WSAEMFILE:             errno = EMFILE; break;
  7854     case WSAENAMETOOLONG:       errno = ENAMETOOLONG; break;
  7855     case WSAENOTEMPTY:          errno = ENOTEMPTY; break;
  7856     case WSAEWOULDBLOCK:        errno = EWOULDBLOCK; break;
  7857     case WSAENOTCONN:           errno = ENOTCONN; break;
  7858     default:                    errno = wsa_err; break;
  7859     }
  7860 }
  7861 
  7862 static void
  7863 check_errno (void)
  7864 {
  7865   h_errno = 0;
  7866   if (winsock_lib != NULL)
  7867     pfn_WSASetLastError (0);
  7868 }
  7869 
  7870 /* Extend strerror to handle the winsock-specific error codes.  */
  7871 struct {
  7872   int errnum;
  7873   const char * msg;
  7874 } _wsa_errlist[] = {
  7875   {WSAEINTR                , "Interrupted function call"},
  7876   {WSAEBADF                , "Bad file descriptor"},
  7877   {WSAEACCES               , "Permission denied"},
  7878   {WSAEFAULT               , "Bad address"},
  7879   {WSAEINVAL               , "Invalid argument"},
  7880   {WSAEMFILE               , "Too many open files"},
  7881 
  7882   {WSAEWOULDBLOCK          , "Resource temporarily unavailable"},
  7883   {WSAEINPROGRESS          , "Operation now in progress"},
  7884   {WSAEALREADY             , "Operation already in progress"},
  7885   {WSAENOTSOCK             , "Socket operation on non-socket"},
  7886   {WSAEDESTADDRREQ         , "Destination address required"},
  7887   {WSAEMSGSIZE             , "Message too long"},
  7888   {WSAEPROTOTYPE           , "Protocol wrong type for socket"},
  7889   {WSAENOPROTOOPT          , "Bad protocol option"},
  7890   {WSAEPROTONOSUPPORT      , "Protocol not supported"},
  7891   {WSAESOCKTNOSUPPORT      , "Socket type not supported"},
  7892   {WSAEOPNOTSUPP           , "Operation not supported"},
  7893   {WSAEPFNOSUPPORT         , "Protocol family not supported"},
  7894   {WSAEAFNOSUPPORT         , "Address family not supported by protocol family"},
  7895   {WSAEADDRINUSE           , "Address already in use"},
  7896   {WSAEADDRNOTAVAIL        , "Cannot assign requested address"},
  7897   {WSAENETDOWN             , "Network is down"},
  7898   {WSAENETUNREACH          , "Network is unreachable"},
  7899   {WSAENETRESET            , "Network dropped connection on reset"},
  7900   {WSAECONNABORTED         , "Software caused connection abort"},
  7901   {WSAECONNRESET           , "Connection reset by peer"},
  7902   {WSAENOBUFS              , "No buffer space available"},
  7903   {WSAEISCONN              , "Socket is already connected"},
  7904   {WSAENOTCONN             , "Socket is not connected"},
  7905   {WSAESHUTDOWN            , "Cannot send after socket shutdown"},
  7906   {WSAETOOMANYREFS         , "Too many references"},        /* not sure */
  7907   {WSAETIMEDOUT            , "Connection timed out"},
  7908   {WSAECONNREFUSED         , "Connection refused"},
  7909   {WSAELOOP                , "Network loop"},               /* not sure */
  7910   {WSAENAMETOOLONG         , "Name is too long"},
  7911   {WSAEHOSTDOWN            , "Host is down"},
  7912   {WSAEHOSTUNREACH         , "No route to host"},
  7913   {WSAENOTEMPTY            , "Buffer not empty"},           /* not sure */
  7914   {WSAEPROCLIM             , "Too many processes"},
  7915   {WSAEUSERS               , "Too many users"},             /* not sure */
  7916   {WSAEDQUOT               , "Double quote in host name"},  /* really not sure */
  7917   {WSAESTALE               , "Data is stale"},              /* not sure */
  7918   {WSAEREMOTE              , "Remote error"},               /* not sure */
  7919 
  7920   {WSASYSNOTREADY          , "Network subsystem is unavailable"},
  7921   {WSAVERNOTSUPPORTED      , "WINSOCK.DLL version out of range"},
  7922   {WSANOTINITIALISED       , "Winsock not initialized successfully"},
  7923   {WSAEDISCON              , "Graceful shutdown in progress"},
  7924 #ifdef WSAENOMORE
  7925   {WSAENOMORE              , "No more operations allowed"}, /* not sure */
  7926   {WSAECANCELLED           , "Operation cancelled"},        /* not sure */
  7927   {WSAEINVALIDPROCTABLE    , "Invalid procedure table from service provider"},
  7928   {WSAEINVALIDPROVIDER     , "Invalid service provider version number"},
  7929   {WSAEPROVIDERFAILEDINIT  , "Unable to initialize a service provider"},
  7930   {WSASYSCALLFAILURE       , "System call failure"},
  7931   {WSASERVICE_NOT_FOUND    , "Service not found"},          /* not sure */
  7932   {WSATYPE_NOT_FOUND       , "Class type not found"},
  7933   {WSA_E_NO_MORE           , "No more resources available"}, /* really not sure */
  7934   {WSA_E_CANCELLED         , "Operation already cancelled"}, /* really not sure */
  7935   {WSAEREFUSED             , "Operation refused"},          /* not sure */
  7936 #endif
  7937 
  7938   {WSAHOST_NOT_FOUND       , "Host not found"},
  7939   {WSATRY_AGAIN            , "Authoritative host not found during name lookup"},
  7940   {WSANO_RECOVERY          , "Non-recoverable error during name lookup"},
  7941   {WSANO_DATA              , "Valid name, no data record of requested type"},
  7942 
  7943   {-1, NULL}
  7944 };
  7945 
  7946 char *
  7947 sys_strerror (int error_no)
  7948 {
  7949   int i;
  7950   static char unknown_msg[40];
  7951 
  7952   if (error_no >= 0 && error_no < sys_nerr)
  7953     return sys_errlist[error_no];
  7954 
  7955   for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
  7956     if (_wsa_errlist[i].errnum == error_no)
  7957       return (char *)_wsa_errlist[i].msg;
  7958 
  7959   sprintf (unknown_msg, "Unidentified error: %d", error_no);
  7960   return unknown_msg;
  7961 }
  7962 
  7963 /* [andrewi 3-May-96] I've had conflicting results using both methods,
  7964    but I believe the method of keeping the socket handle separate (and
  7965    insuring it is not inheritable) is the correct one. */
  7966 
  7967 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
  7968 
  7969 static int socket_to_fd (SOCKET s);
  7970 
  7971 int
  7972 sys_socket (int af, int type, int protocol)
  7973 {
  7974   SOCKET s;
  7975 
  7976   if (winsock_lib == NULL)
  7977     {
  7978       errno = ENETDOWN;
  7979       return -1;
  7980     }
  7981 
  7982   check_errno ();
  7983 
  7984   /* call the real socket function */
  7985   s = pfn_socket (af, type, protocol);
  7986 
  7987   if (s != INVALID_SOCKET)
  7988     return socket_to_fd (s);
  7989 
  7990   set_errno ();
  7991   return -1;
  7992 }
  7993 
  7994 /* Convert a SOCKET to a file descriptor.  */
  7995 static int
  7996 socket_to_fd (SOCKET s)
  7997 {
  7998   int fd;
  7999   child_process * cp;
  8000 
  8001   /* Although under NT 3.5 _open_osfhandle will accept a socket
  8002      handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
  8003      that does not work under NT 3.1.  However, we can get the same
  8004      effect by using a backdoor function to replace an existing
  8005      descriptor handle with the one we want. */
  8006 
  8007   /* allocate a file descriptor (with appropriate flags) */
  8008   fd = _open ("NUL:", _O_RDWR);
  8009   if (fd >= 0)
  8010     {
  8011       /* Make a non-inheritable copy of the socket handle.  Note
  8012          that it is possible that sockets aren't actually kernel
  8013          handles, which appears to be the case on Windows 9x when
  8014          the MS Proxy winsock client is installed.  */
  8015       {
  8016         /* Apparently there is a bug in NT 3.51 with some service
  8017            packs, which prevents using DuplicateHandle to make a
  8018            socket handle non-inheritable (causes WSACleanup to
  8019            hang).  The work-around is to use SetHandleInformation
  8020            instead if it is available and implemented. */
  8021         if (pfn_SetHandleInformation)
  8022           {
  8023             pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
  8024           }
  8025         else
  8026           {
  8027             HANDLE parent = GetCurrentProcess ();
  8028             HANDLE new_s = INVALID_HANDLE_VALUE;
  8029 
  8030             if (DuplicateHandle (parent,
  8031                                  (HANDLE) s,
  8032                                  parent,
  8033                                  &new_s,
  8034                                  0,
  8035                                  FALSE,
  8036                                  DUPLICATE_SAME_ACCESS))
  8037               {
  8038                 /* It is possible that DuplicateHandle succeeds even
  8039                    though the socket wasn't really a kernel handle,
  8040                    because a real handle has the same value.  So
  8041                    test whether the new handle really is a socket.  */
  8042                 unsigned long nonblocking = 0;
  8043                 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
  8044                   {
  8045                     pfn_closesocket (s);
  8046                     s = (SOCKET) new_s;
  8047                   }
  8048                 else
  8049                   {
  8050                     CloseHandle (new_s);
  8051                   }
  8052               }
  8053           }
  8054       }
  8055       eassert (fd < MAXDESC);
  8056       fd_info[fd].hnd = (HANDLE) s;
  8057 
  8058       /* set our own internal flags */
  8059       fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
  8060 
  8061       cp = new_child ();
  8062       if (cp)
  8063         {
  8064           cp->fd = fd;
  8065           cp->status = STATUS_READ_ACKNOWLEDGED;
  8066 
  8067           /* attach child_process to fd_info */
  8068           if (fd_info[ fd ].cp != NULL)
  8069             {
  8070               DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
  8071               emacs_abort ();
  8072             }
  8073 
  8074           fd_info[ fd ].cp = cp;
  8075 
  8076           /* success! */
  8077           winsock_inuse++;      /* count open sockets */
  8078           return fd;
  8079         }
  8080 
  8081       /* clean up */
  8082       _close (fd);
  8083     }
  8084   else
  8085   pfn_closesocket (s);
  8086   errno = EMFILE;
  8087   return -1;
  8088 }
  8089 
  8090 int
  8091 sys_bind (int s, const struct sockaddr * addr, int namelen)
  8092 {
  8093   if (winsock_lib == NULL)
  8094     {
  8095       errno = ENOTSOCK;
  8096       return SOCKET_ERROR;
  8097     }
  8098 
  8099   check_errno ();
  8100   if (fd_info[s].flags & FILE_SOCKET)
  8101     {
  8102       int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
  8103       if (rc == SOCKET_ERROR)
  8104         set_errno ();
  8105       return rc;
  8106     }
  8107   errno = ENOTSOCK;
  8108   return SOCKET_ERROR;
  8109 }
  8110 
  8111 int
  8112 sys_connect (int s, const struct sockaddr * name, int namelen)
  8113 {
  8114   if (winsock_lib == NULL)
  8115     {
  8116       errno = ENOTSOCK;
  8117       return SOCKET_ERROR;
  8118     }
  8119 
  8120   check_errno ();
  8121   if (fd_info[s].flags & FILE_SOCKET)
  8122     {
  8123       int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
  8124       if (rc == SOCKET_ERROR)
  8125         {
  8126           set_errno ();
  8127           /* If this is a non-blocking 'connect', set the bit in flags
  8128              that will tell reader_thread to wait for connection
  8129              before trying to read.  */
  8130           if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
  8131             {
  8132               errno = EINPROGRESS; /* that's what process.c expects */
  8133               fd_info[s].flags |= FILE_CONNECT;
  8134             }
  8135         }
  8136       return rc;
  8137     }
  8138   errno = ENOTSOCK;
  8139   return SOCKET_ERROR;
  8140 }
  8141 
  8142 u_short
  8143 sys_htons (u_short hostshort)
  8144 {
  8145   return (winsock_lib != NULL) ?
  8146     pfn_htons (hostshort) : hostshort;
  8147 }
  8148 
  8149 u_short
  8150 sys_ntohs (u_short netshort)
  8151 {
  8152   return (winsock_lib != NULL) ?
  8153     pfn_ntohs (netshort) : netshort;
  8154 }
  8155 u_long
  8156 sys_htonl (u_long hostlong)
  8157 {
  8158   return (winsock_lib != NULL) ?
  8159     pfn_htonl (hostlong) : hostlong;
  8160 }
  8161 
  8162 u_long
  8163 sys_ntohl (u_long netlong)
  8164 {
  8165   return (winsock_lib != NULL) ?
  8166     pfn_ntohl (netlong) : netlong;
  8167 }
  8168 
  8169 unsigned long
  8170 sys_inet_addr (const char * cp)
  8171 {
  8172   return (winsock_lib != NULL) ?
  8173     pfn_inet_addr (cp) : INADDR_NONE;
  8174 }
  8175 
  8176 int
  8177 sys_gethostname (char * name, int namelen)
  8178 {
  8179   if (winsock_lib != NULL)
  8180     {
  8181       int retval;
  8182 
  8183       check_errno ();
  8184       retval = pfn_gethostname (name, namelen);
  8185       if (retval == SOCKET_ERROR)
  8186         set_errno ();
  8187       return retval;
  8188     }
  8189 
  8190   if (namelen > MAX_COMPUTERNAME_LENGTH)
  8191     return !GetComputerName (name, (DWORD *)&namelen);
  8192 
  8193   errno = EFAULT;
  8194   return SOCKET_ERROR;
  8195 }
  8196 
  8197 struct hostent *
  8198 sys_gethostbyname (const char * name)
  8199 {
  8200   struct hostent * host;
  8201   int h_err = h_errno;
  8202 
  8203   if (winsock_lib == NULL)
  8204     {
  8205       h_errno = NO_RECOVERY;
  8206       errno = ENETDOWN;
  8207       return NULL;
  8208     }
  8209 
  8210   check_errno ();
  8211   host = pfn_gethostbyname (name);
  8212   if (!host)
  8213     {
  8214       set_errno ();
  8215       h_errno = errno;
  8216     }
  8217   else
  8218     h_errno = h_err;
  8219   return host;
  8220 }
  8221 
  8222 struct servent *
  8223 sys_getservbyname (const char * name, const char * proto)
  8224 {
  8225   struct servent * serv;
  8226 
  8227   if (winsock_lib == NULL)
  8228     {
  8229       errno = ENETDOWN;
  8230       return NULL;
  8231     }
  8232 
  8233   check_errno ();
  8234   serv = pfn_getservbyname (name, proto);
  8235   if (!serv)
  8236     set_errno ();
  8237   return serv;
  8238 }
  8239 
  8240 int
  8241 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
  8242 {
  8243   if (winsock_lib == NULL)
  8244     {
  8245       errno = ENETDOWN;
  8246       return SOCKET_ERROR;
  8247     }
  8248 
  8249   check_errno ();
  8250   if (fd_info[s].flags & FILE_SOCKET)
  8251     {
  8252       int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
  8253       if (rc == SOCKET_ERROR)
  8254         set_errno ();
  8255       return rc;
  8256     }
  8257   errno = ENOTSOCK;
  8258   return SOCKET_ERROR;
  8259 }
  8260 
  8261 int
  8262 sys_getaddrinfo (const char *node, const char *service,
  8263                  const struct addrinfo *hints, struct addrinfo **res)
  8264 {
  8265   int rc;
  8266 
  8267   if (winsock_lib == NULL)
  8268     {
  8269       errno = ENETDOWN;
  8270       return SOCKET_ERROR;
  8271     }
  8272 
  8273   check_errno ();
  8274   if (pfn_getaddrinfo)
  8275     rc = pfn_getaddrinfo (node, service, hints, res);
  8276   else
  8277     {
  8278       int port = 0;
  8279       struct hostent *host_info;
  8280       struct gai_storage {
  8281         struct addrinfo addrinfo;
  8282         struct sockaddr_in sockaddr_in;
  8283       } *gai_storage;
  8284 
  8285       /* We don't (yet) support any flags, as Emacs doesn't need that.  */
  8286       if (hints && hints->ai_flags != 0)
  8287         return WSAEINVAL;
  8288       /* NODE cannot be NULL, since process.c has fallbacks for that.  */
  8289       if (!node)
  8290         return WSAHOST_NOT_FOUND;
  8291 
  8292       if (service)
  8293         {
  8294           const char *protocol =
  8295             (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
  8296           struct servent *srv = sys_getservbyname (service, protocol);
  8297 
  8298           if (srv)
  8299             port = srv->s_port;
  8300           else if (*service >= '0' && *service <= '9')
  8301             {
  8302               char *endp;
  8303 
  8304               port = strtoul (service, &endp, 10);
  8305               if (*endp || port > 65536)
  8306                 return WSAHOST_NOT_FOUND;
  8307               port = sys_htons ((unsigned short) port);
  8308             }
  8309           else
  8310             return WSAHOST_NOT_FOUND;
  8311         }
  8312 
  8313       gai_storage = xzalloc (sizeof *gai_storage);
  8314       gai_storage->sockaddr_in.sin_port = port;
  8315       host_info = sys_gethostbyname (node);
  8316       if (host_info)
  8317         {
  8318           memcpy (&gai_storage->sockaddr_in.sin_addr,
  8319                   host_info->h_addr, host_info->h_length);
  8320           gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
  8321         }
  8322       else
  8323         {
  8324           /* Attempt to interpret host as numeric inet address.  */
  8325           unsigned long numeric_addr = sys_inet_addr (node);
  8326 
  8327           if (numeric_addr == -1)
  8328             {
  8329               free (gai_storage);
  8330               return WSAHOST_NOT_FOUND;
  8331             }
  8332 
  8333           memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
  8334                   sizeof (gai_storage->sockaddr_in.sin_addr));
  8335           gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
  8336         }
  8337 
  8338       gai_storage->addrinfo.ai_addr =
  8339         (struct sockaddr *)&gai_storage->sockaddr_in;
  8340       gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
  8341       gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
  8342       gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
  8343       gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
  8344       gai_storage->addrinfo.ai_next = NULL;
  8345 
  8346       *res = &gai_storage->addrinfo;
  8347       rc = 0;
  8348     }
  8349 
  8350   return rc;
  8351 }
  8352 
  8353 void
  8354 sys_freeaddrinfo (struct addrinfo *ai)
  8355 {
  8356   if (winsock_lib == NULL)
  8357     {
  8358       errno = ENETDOWN;
  8359       return;
  8360     }
  8361 
  8362   check_errno ();
  8363   if (pfn_freeaddrinfo)
  8364     pfn_freeaddrinfo (ai);
  8365   else
  8366     {
  8367       eassert (ai->ai_next == NULL);
  8368       xfree (ai);
  8369     }
  8370 }
  8371 
  8372 int
  8373 sys_shutdown (int s, int how)
  8374 {
  8375   if (winsock_lib == NULL)
  8376     {
  8377       errno = ENETDOWN;
  8378       return SOCKET_ERROR;
  8379     }
  8380 
  8381   check_errno ();
  8382   if (fd_info[s].flags & FILE_SOCKET)
  8383     {
  8384       int rc = pfn_shutdown (SOCK_HANDLE (s), how);
  8385       if (rc == SOCKET_ERROR)
  8386         set_errno ();
  8387       return rc;
  8388     }
  8389   errno = ENOTSOCK;
  8390   return SOCKET_ERROR;
  8391 }
  8392 
  8393 int
  8394 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
  8395 {
  8396   if (winsock_lib == NULL)
  8397     {
  8398       errno = ENETDOWN;
  8399       return SOCKET_ERROR;
  8400     }
  8401 
  8402   check_errno ();
  8403   if (fd_info[s].flags & FILE_SOCKET)
  8404     {
  8405       int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
  8406                                (const char *)optval, optlen);
  8407       if (rc == SOCKET_ERROR)
  8408         set_errno ();
  8409       return rc;
  8410     }
  8411   errno = ENOTSOCK;
  8412   return SOCKET_ERROR;
  8413 }
  8414 
  8415 int
  8416 sys_listen (int s, int backlog)
  8417 {
  8418   if (winsock_lib == NULL)
  8419     {
  8420       errno = ENETDOWN;
  8421       return SOCKET_ERROR;
  8422     }
  8423 
  8424   check_errno ();
  8425   if (fd_info[s].flags & FILE_SOCKET)
  8426     {
  8427       int rc = pfn_listen (SOCK_HANDLE (s), backlog);
  8428       if (rc == SOCKET_ERROR)
  8429         set_errno ();
  8430       else
  8431         fd_info[s].flags |= FILE_LISTEN;
  8432       return rc;
  8433     }
  8434   errno = ENOTSOCK;
  8435   return SOCKET_ERROR;
  8436 }
  8437 
  8438 int
  8439 sys_getsockname (int s, struct sockaddr * name, int * namelen)
  8440 {
  8441   if (winsock_lib == NULL)
  8442     {
  8443       errno = ENETDOWN;
  8444       return SOCKET_ERROR;
  8445     }
  8446 
  8447   check_errno ();
  8448   if (fd_info[s].flags & FILE_SOCKET)
  8449     {
  8450       int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
  8451       if (rc == SOCKET_ERROR)
  8452         set_errno ();
  8453       return rc;
  8454     }
  8455   errno = ENOTSOCK;
  8456   return SOCKET_ERROR;
  8457 }
  8458 
  8459 int
  8460 sys_accept (int s, struct sockaddr * addr, int * addrlen)
  8461 {
  8462   if (winsock_lib == NULL)
  8463     {
  8464       errno = ENETDOWN;
  8465       return -1;
  8466     }
  8467 
  8468   check_errno ();
  8469   if (fd_info[s].flags & FILE_LISTEN)
  8470     {
  8471       SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
  8472       int fd = -1;
  8473       if (t == INVALID_SOCKET)
  8474         set_errno ();
  8475       else
  8476         fd = socket_to_fd (t);
  8477 
  8478       if (fd >= 0)
  8479         {
  8480           fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
  8481           ResetEvent (fd_info[s].cp->char_avail);
  8482         }
  8483       return fd;
  8484     }
  8485   errno = ENOTSOCK;
  8486   return -1;
  8487 }
  8488 
  8489 int
  8490 sys_recvfrom (int s, char * buf, int len, int flags,
  8491               struct sockaddr * from, int * fromlen)
  8492 {
  8493   if (winsock_lib == NULL)
  8494     {
  8495       errno = ENETDOWN;
  8496       return SOCKET_ERROR;
  8497     }
  8498 
  8499   check_errno ();
  8500   if (fd_info[s].flags & FILE_SOCKET)
  8501     {
  8502       int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
  8503       if (rc == SOCKET_ERROR)
  8504         set_errno ();
  8505       return rc;
  8506     }
  8507   errno = ENOTSOCK;
  8508   return SOCKET_ERROR;
  8509 }
  8510 
  8511 int
  8512 sys_sendto (int s, const char * buf, int len, int flags,
  8513             const struct sockaddr * to, int tolen)
  8514 {
  8515   if (winsock_lib == NULL)
  8516     {
  8517       errno = ENETDOWN;
  8518       return SOCKET_ERROR;
  8519     }
  8520 
  8521   check_errno ();
  8522   if (fd_info[s].flags & FILE_SOCKET)
  8523     {
  8524       int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
  8525       if (rc == SOCKET_ERROR)
  8526         set_errno ();
  8527       return rc;
  8528     }
  8529   errno = ENOTSOCK;
  8530   return SOCKET_ERROR;
  8531 }
  8532 
  8533 /* Windows does not have an fcntl function.  Provide an implementation
  8534    good enough for Emacs.  */
  8535 int
  8536 fcntl (int s, int cmd, int options)
  8537 {
  8538   /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
  8539      invoked in a context where fd1 is closed and all descriptors less
  8540      than fd1 are open, so sys_dup is an adequate implementation.  */
  8541   if (cmd == F_DUPFD_CLOEXEC)
  8542     return sys_dup (s);
  8543 
  8544   check_errno ();
  8545   if (fd_info[s].flags & FILE_SOCKET)
  8546     {
  8547       if (winsock_lib == NULL)
  8548         {
  8549           errno = ENETDOWN;
  8550           return -1;
  8551         }
  8552 
  8553       if (cmd == F_SETFL && options == O_NONBLOCK)
  8554         {
  8555           unsigned long nblock = 1;
  8556           int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
  8557           if (rc == SOCKET_ERROR)
  8558             set_errno ();
  8559           /* Keep track of the fact that we set this to non-blocking.  */
  8560           fd_info[s].flags |= FILE_NDELAY;
  8561           return rc;
  8562         }
  8563       else
  8564         {
  8565           errno = EINVAL;
  8566           return SOCKET_ERROR;
  8567         }
  8568     }
  8569   else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
  8570            == (FILE_PIPE | FILE_WRITE))
  8571     {
  8572       /* Force our writes to pipes be non-blocking.  */
  8573       if (cmd == F_SETFL && options == O_NONBLOCK)
  8574         {
  8575           HANDLE h = (HANDLE)_get_osfhandle (s);
  8576           DWORD pipe_mode = PIPE_NOWAIT;
  8577 
  8578           if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
  8579             {
  8580               DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
  8581               return SOCKET_ERROR;
  8582             }
  8583           fd_info[s].flags |= FILE_NDELAY;
  8584           return 0;
  8585         }
  8586       else
  8587         {
  8588           errno = EINVAL;
  8589           return SOCKET_ERROR;
  8590         }
  8591     }
  8592   errno = ENOTSOCK;
  8593   return SOCKET_ERROR;
  8594 }
  8595 
  8596 
  8597 /* Shadow main io functions: we need to handle pipes and sockets more
  8598    intelligently.  */
  8599 
  8600 int
  8601 sys_close (int fd)
  8602 {
  8603   int rc = -1;
  8604   bool reader_thread_exited = false;
  8605 
  8606   if (fd < 0)
  8607     {
  8608       errno = EBADF;
  8609       return -1;
  8610     }
  8611 
  8612   if (fd < MAXDESC && fd_info[fd].cp)
  8613     {
  8614       child_process * cp = fd_info[fd].cp;
  8615       DWORD thrd_status = STILL_ACTIVE;
  8616 
  8617       /* Thread handle will be NULL if we already called delete_child.  */
  8618       if (cp->thrd != NULL
  8619           && GetExitCodeThread (cp->thrd, &thrd_status)
  8620           && thrd_status != STILL_ACTIVE)
  8621         reader_thread_exited = true;
  8622 
  8623       fd_info[fd].cp = NULL;
  8624 
  8625       if (CHILD_ACTIVE (cp))
  8626         {
  8627           /* if last descriptor to active child_process then cleanup */
  8628           int i;
  8629           for (i = 0; i < MAXDESC; i++)
  8630             {
  8631               if (i == fd)
  8632                 continue;
  8633               if (fd_info[i].cp == cp)
  8634                 break;
  8635             }
  8636           if (i == MAXDESC)
  8637             {
  8638               if (fd_info[fd].flags & FILE_SOCKET)
  8639                 {
  8640                   if (winsock_lib == NULL) emacs_abort ();
  8641 
  8642                   pfn_shutdown (SOCK_HANDLE (fd), 2);
  8643                   rc = pfn_closesocket (SOCK_HANDLE (fd));
  8644 
  8645                   winsock_inuse--; /* count open sockets */
  8646                 }
  8647               /* If the process handle is NULL, it's either a socket
  8648                  or serial connection, or a subprocess that was
  8649                  already reaped by reap_subprocess, but whose
  8650                  resources were not yet freed, because its output was
  8651                  not fully read yet by the time it was reaped.  (This
  8652                  usually happens with async subprocesses whose output
  8653                  is being read by Emacs.)  Otherwise, this process was
  8654                  not reaped yet, so we set its FD to a negative value
  8655                  to make sure sys_select will eventually get to
  8656                  calling the SIGCHLD handler for it, which will then
  8657                  invoke waitpid and reap_subprocess.  */
  8658               if (cp->procinfo.hProcess == NULL)
  8659                 delete_child (cp);
  8660               else
  8661                 cp->fd = -1;
  8662             }
  8663         }
  8664     }
  8665 
  8666   /* Note that sockets do not need special treatment here (at least on
  8667      NT and Windows 95 using the standard tcp/ip stacks) - it appears that
  8668      closesocket is equivalent to CloseHandle, which is to be expected
  8669      because socket handles are fully fledged kernel handles. */
  8670   if (fd < MAXDESC)
  8671     {
  8672       if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0
  8673           /* If the reader thread already exited, close the descriptor,
  8674              since otherwise no one will close it, and we will be
  8675              leaking descriptors.  */
  8676           || reader_thread_exited)
  8677         {
  8678           fd_info[fd].flags = 0;
  8679           rc = _close (fd);
  8680         }
  8681       else
  8682         {
  8683           /* We don't close here descriptors open by pipe processes
  8684              for reading from the pipe when the reader thread might
  8685              still be running, since that thread might be stuck in
  8686              _sys_read_ahead, and then we will hang here.  If the
  8687              reader thread exits normally, it will close the
  8688              descriptor; otherwise we will leave a zombie thread
  8689              hanging around.  */
  8690           rc = 0;
  8691           /* Leave the flag set for the reader thread to close the
  8692              descriptor.  */
  8693           fd_info[fd].flags = FILE_DONT_CLOSE;
  8694         }
  8695     }
  8696 
  8697   return rc;
  8698 }
  8699 
  8700 int
  8701 sys_dup (int fd)
  8702 {
  8703   int new_fd;
  8704 
  8705   new_fd = _dup (fd);
  8706   if (new_fd >= 0 && new_fd < MAXDESC)
  8707     {
  8708       /* duplicate our internal info as well */
  8709       fd_info[new_fd] = fd_info[fd];
  8710     }
  8711   return new_fd;
  8712 }
  8713 
  8714 int
  8715 sys_dup2 (int src, int dst)
  8716 {
  8717   int rc;
  8718 
  8719   if (dst < 0 || dst >= MAXDESC)
  8720     {
  8721       errno = EBADF;
  8722       return -1;
  8723     }
  8724 
  8725   /* MS _dup2 seems to have weird side effect when invoked with 2
  8726      identical arguments: an attempt to fclose the corresponding stdio
  8727      stream after that hangs (we do close standard streams in
  8728      init_ntproc).  Attempt to avoid that by not calling _dup2 that
  8729      way: if SRC is valid, we know that dup2 should be a no-op, so do
  8730      nothing and return DST.  */
  8731   if (src == dst)
  8732     {
  8733       if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
  8734         {
  8735           errno = EBADF;
  8736           return -1;
  8737         }
  8738       return dst;
  8739     }
  8740 
  8741   /* Make sure we close the destination first if it's a pipe or socket.  */
  8742   if (fd_info[dst].flags != 0)
  8743     sys_close (dst);
  8744 
  8745   rc = _dup2 (src, dst);
  8746   if (rc == 0)
  8747     {
  8748       /* Duplicate our internal info as well.  */
  8749       fd_info[dst] = fd_info[src];
  8750     }
  8751   return rc == 0 ? dst : rc;
  8752 }
  8753 
  8754 int
  8755 pipe2 (int * phandles, int pipe2_flags)
  8756 {
  8757   int rc;
  8758   unsigned flags;
  8759   unsigned pipe_size = 0;
  8760 
  8761   eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
  8762 
  8763   /* Allow Lisp to override the default buffer size of the pipe.  */
  8764   if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
  8765     pipe_size = w32_pipe_buffer_size;
  8766 
  8767   /* make pipe handles non-inheritable; when we spawn a child, we
  8768      replace the relevant handle with an inheritable one.  Also put
  8769      pipes into binary mode; we will do text mode translation ourselves
  8770      if required.  */
  8771   rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
  8772 
  8773   if (rc == 0)
  8774     {
  8775       /* Protect against overflow, since Windows can open more handles than
  8776          our fd_info array has room for.  */
  8777       if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
  8778         {
  8779           _close (phandles[0]);
  8780           _close (phandles[1]);
  8781           /* Since we close the handles, set them to -1, so as to
  8782              avoid an assertion violation if the caller then tries to
  8783              close the handle again (emacs_close will abort otherwise
  8784              if errno is EBADF).  */
  8785           phandles[0] = phandles[1] = -1;
  8786           errno = EMFILE;
  8787           rc = -1;
  8788         }
  8789       else
  8790         {
  8791           flags = FILE_PIPE | FILE_READ | FILE_BINARY;
  8792           fd_info[phandles[0]].flags = flags;
  8793 
  8794           flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
  8795           fd_info[phandles[1]].flags = flags;
  8796         }
  8797     }
  8798 
  8799   return rc;
  8800 }
  8801 
  8802 /* Function to do blocking read of one byte, needed to implement
  8803    select.  It is only allowed on communication ports, sockets, or
  8804    pipes. */
  8805 int
  8806 _sys_read_ahead (int fd)
  8807 {
  8808   child_process * cp;
  8809   int rc = 0;
  8810 
  8811   if (fd < 0 || fd >= MAXDESC)
  8812     return STATUS_READ_ERROR;
  8813 
  8814   cp = fd_info[fd].cp;
  8815 
  8816   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
  8817     return STATUS_READ_ERROR;
  8818 
  8819   if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
  8820       || (fd_info[fd].flags & FILE_READ) == 0)
  8821     {
  8822       DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
  8823       emacs_abort ();
  8824     }
  8825 
  8826   if ((fd_info[fd].flags & FILE_CONNECT) != 0)
  8827     DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
  8828   cp->status = STATUS_READ_IN_PROGRESS;
  8829 
  8830   if (fd_info[fd].flags & FILE_PIPE)
  8831     {
  8832       rc = _read (fd, &cp->chr, sizeof (char));
  8833 
  8834       /* Optionally give subprocess time to buffer some more output
  8835          for us before reporting that input is available; we may need
  8836          this because Windows 9X connects DOS programs to pipes by
  8837          making the pipe appear to be the normal console stdout -- as
  8838          a result most DOS programs will write to stdout without
  8839          buffering, i.e., one character at a time.  Even some W32
  8840          programs do this -- "dir" in a command shell on NT is very
  8841          slow if we don't do this.  */
  8842       if (rc > 0)
  8843         {
  8844           int wait = w32_pipe_read_delay;
  8845 
  8846           if (wait > 0)
  8847             Sleep (wait);
  8848           else if (wait < 0)
  8849             while (++wait <= 0)
  8850               /* Yield remainder of our time slice, effectively giving a
  8851                  temporary priority boost to the child process. */
  8852               Sleep (0);
  8853         }
  8854     }
  8855   else if (fd_info[fd].flags & FILE_SERIAL)
  8856     {
  8857       HANDLE hnd = fd_info[fd].hnd;
  8858       OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
  8859       COMMTIMEOUTS ct;
  8860 
  8861       /* Configure timeouts for blocking read.  */
  8862       if (!GetCommTimeouts (hnd, &ct))
  8863         {
  8864           cp->status = STATUS_READ_ERROR;
  8865           return STATUS_READ_ERROR;
  8866         }
  8867       ct.ReadIntervalTimeout            = 0;
  8868       ct.ReadTotalTimeoutMultiplier     = 0;
  8869       ct.ReadTotalTimeoutConstant       = 0;
  8870       if (!SetCommTimeouts (hnd, &ct))
  8871         {
  8872           cp->status = STATUS_READ_ERROR;
  8873           return STATUS_READ_ERROR;
  8874         }
  8875 
  8876       if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
  8877         {
  8878           if (GetLastError () != ERROR_IO_PENDING)
  8879             {
  8880               cp->status = STATUS_READ_ERROR;
  8881               return STATUS_READ_ERROR;
  8882             }
  8883           if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
  8884             {
  8885               cp->status = STATUS_READ_ERROR;
  8886               return STATUS_READ_ERROR;
  8887             }
  8888         }
  8889     }
  8890   else if (fd_info[fd].flags & FILE_SOCKET)
  8891     {
  8892       unsigned long nblock = 0;
  8893       /* We always want this to block, so temporarily disable NDELAY.  */
  8894       if (fd_info[fd].flags & FILE_NDELAY)
  8895         pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
  8896 
  8897       rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
  8898 
  8899       if (fd_info[fd].flags & FILE_NDELAY)
  8900         {
  8901           nblock = 1;
  8902           pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
  8903         }
  8904     }
  8905 
  8906   if (rc == sizeof (char))
  8907     cp->status = STATUS_READ_SUCCEEDED;
  8908   else
  8909     cp->status = STATUS_READ_FAILED;
  8910 
  8911   return cp->status;
  8912 }
  8913 
  8914 int
  8915 _sys_wait_accept (int fd)
  8916 {
  8917   HANDLE hEv;
  8918   child_process * cp;
  8919   int rc;
  8920 
  8921   if (fd < 0 || fd >= MAXDESC)
  8922     return STATUS_READ_ERROR;
  8923 
  8924   cp = fd_info[fd].cp;
  8925 
  8926   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
  8927     return STATUS_READ_ERROR;
  8928 
  8929   cp->status = STATUS_READ_FAILED;
  8930 
  8931   hEv = pfn_WSACreateEvent ();
  8932   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
  8933   if (rc != SOCKET_ERROR)
  8934     {
  8935       do {
  8936         rc = WaitForSingleObject (hEv, 500);
  8937         Sleep (5);
  8938       } while (rc == WAIT_TIMEOUT
  8939                && cp->status != STATUS_READ_ERROR
  8940                && cp->char_avail);
  8941       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
  8942       if (rc == WAIT_OBJECT_0)
  8943         cp->status = STATUS_READ_SUCCEEDED;
  8944     }
  8945   pfn_WSACloseEvent (hEv);
  8946 
  8947   return cp->status;
  8948 }
  8949 
  8950 int
  8951 _sys_wait_connect (int fd)
  8952 {
  8953   HANDLE hEv;
  8954   child_process * cp;
  8955   int rc;
  8956 
  8957   if (fd < 0 || fd >= MAXDESC)
  8958     return STATUS_READ_ERROR;
  8959 
  8960   cp = fd_info[fd].cp;
  8961   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
  8962     return STATUS_READ_ERROR;
  8963 
  8964   cp->status = STATUS_READ_FAILED;
  8965 
  8966   hEv = pfn_WSACreateEvent ();
  8967   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
  8968   if (rc != SOCKET_ERROR)
  8969     {
  8970       do {
  8971         rc = WaitForSingleObject (hEv, 500);
  8972         Sleep (5);
  8973       } while (rc == WAIT_TIMEOUT
  8974                && cp->status != STATUS_READ_ERROR
  8975                && cp->char_avail);
  8976       if (rc == WAIT_OBJECT_0)
  8977         {
  8978           /* We've got an event, but it could be a successful
  8979              connection, or it could be a failure.  Find out
  8980              which one is it.  */
  8981           WSANETWORKEVENTS events;
  8982 
  8983           pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
  8984           if ((events.lNetworkEvents & FD_CONNECT) != 0
  8985               && events.iErrorCode[FD_CONNECT_BIT])
  8986             {
  8987               cp->status = STATUS_CONNECT_FAILED;
  8988               cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
  8989             }
  8990           else
  8991             {
  8992               cp->status = STATUS_READ_SUCCEEDED;
  8993               cp->errcode = 0;
  8994             }
  8995         }
  8996       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
  8997     }
  8998   else
  8999     pfn_WSACloseEvent (hEv);
  9000 
  9001   return cp->status;
  9002 }
  9003 
  9004 int
  9005 sys_read (int fd, char * buffer, unsigned int count)
  9006 {
  9007   int nchars;
  9008   int to_read;
  9009   DWORD waiting;
  9010   char * orig_buffer = buffer;
  9011 
  9012   if (fd < 0)
  9013     {
  9014       errno = EBADF;
  9015       return -1;
  9016     }
  9017 
  9018   if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
  9019     {
  9020       child_process *cp = fd_info[fd].cp;
  9021 
  9022       if ((fd_info[fd].flags & FILE_READ) == 0)
  9023         {
  9024           errno = EBADF;
  9025           return -1;
  9026         }
  9027 
  9028       nchars = 0;
  9029 
  9030       /* re-read CR carried over from last read */
  9031       if (fd_info[fd].flags & FILE_LAST_CR)
  9032         {
  9033           if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
  9034           *buffer++ = 0x0d;
  9035           count--;
  9036           nchars++;
  9037           fd_info[fd].flags &= ~FILE_LAST_CR;
  9038         }
  9039 
  9040       /* presence of a child_process structure means we are operating in
  9041          non-blocking mode - otherwise we just call _read directly.
  9042          Note that the child_process structure might be missing because
  9043          reap_subprocess has been called; in this case the pipe is
  9044          already broken, so calling _read on it is okay. */
  9045       if (cp)
  9046         {
  9047           int current_status = cp->status;
  9048 
  9049           switch (current_status)
  9050             {
  9051             case STATUS_READ_FAILED:
  9052             case STATUS_READ_ERROR:
  9053               /* report normal EOF if nothing in buffer */
  9054               if (nchars <= 0)
  9055                 fd_info[fd].flags |= FILE_AT_EOF;
  9056               return nchars;
  9057 
  9058             case STATUS_READ_READY:
  9059             case STATUS_READ_IN_PROGRESS:
  9060 #if 0
  9061               /* This happens all the time during GnuTLS handshake
  9062                  with the remote, evidently because GnuTLS waits for
  9063                  the read to complete by retrying the read operation
  9064                  upon EAGAIN.  So I'm disabling the DebPrint to avoid
  9065                  wasting cycles on something that is not a real
  9066                  problem.  Enable if you need to debug something that
  9067                  bumps into this.  */
  9068               DebPrint (("sys_read called when read is in progress %d\n",
  9069                          current_status));
  9070 #endif
  9071               errno = EWOULDBLOCK;
  9072               return -1;
  9073 
  9074             case STATUS_READ_SUCCEEDED:
  9075               /* consume read-ahead char */
  9076               *buffer++ = cp->chr;
  9077               count--;
  9078               nchars++;
  9079               cp->status = STATUS_READ_ACKNOWLEDGED;
  9080               ResetEvent (cp->char_avail);
  9081 
  9082             case STATUS_READ_ACKNOWLEDGED:
  9083             case STATUS_CONNECT_FAILED:
  9084               break;
  9085 
  9086             default:
  9087               DebPrint (("sys_read: bad status %d\n", current_status));
  9088               errno = EBADF;
  9089               return -1;
  9090             }
  9091 
  9092           if (fd_info[fd].flags & FILE_PIPE)
  9093             {
  9094               PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
  9095               to_read = min (waiting, (DWORD) count);
  9096 
  9097               if (to_read > 0)
  9098                 nchars += _read (fd, buffer, to_read);
  9099             }
  9100           else if (fd_info[fd].flags & FILE_SERIAL)
  9101             {
  9102               HANDLE hnd = fd_info[fd].hnd;
  9103               OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
  9104               int rc = 0;
  9105               COMMTIMEOUTS ct;
  9106 
  9107               if (count > 0)
  9108                 {
  9109                   /* Configure timeouts for non-blocking read.  */
  9110                   if (!GetCommTimeouts (hnd, &ct))
  9111                     {
  9112                       errno = EIO;
  9113                       return -1;
  9114                     }
  9115                   ct.ReadIntervalTimeout         = MAXDWORD;
  9116                   ct.ReadTotalTimeoutMultiplier  = 0;
  9117                   ct.ReadTotalTimeoutConstant    = 0;
  9118                   if (!SetCommTimeouts (hnd, &ct))
  9119                     {
  9120                       errno = EIO;
  9121                       return -1;
  9122                     }
  9123 
  9124                   if (!ResetEvent (ovl->hEvent))
  9125                     {
  9126                       errno = EIO;
  9127                       return -1;
  9128                     }
  9129                   if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
  9130                     {
  9131                       if (GetLastError () != ERROR_IO_PENDING)
  9132                         {
  9133                           errno = EIO;
  9134                           return -1;
  9135                         }
  9136                       if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
  9137                         {
  9138                           errno = EIO;
  9139                           return -1;
  9140                         }
  9141                     }
  9142                   nchars += rc;
  9143                 }
  9144             }
  9145           else /* FILE_SOCKET */
  9146             {
  9147               if (winsock_lib == NULL) emacs_abort ();
  9148 
  9149               /* When a non-blocking 'connect' call fails,
  9150                  wait_reading_process_output detects this by calling
  9151                  'getpeername', and then attempts to obtain the connection
  9152                  error code by trying to read 1 byte from the socket.  If
  9153                  we try to serve that read by calling 'recv' below, the
  9154                  error we get is a generic WSAENOTCONN, not the actual
  9155                  connection error.  So instead, we use the actual error
  9156                  code stashed by '_sys_wait_connect' in cp->errcode.
  9157                  Alternatively, we could have used 'getsockopt', like on
  9158                  GNU/Linux, but: (a) I have no idea whether the winsock
  9159                  version could hang, as it does "on some systems" (see the
  9160                  comment in process.c); and (b) 'getsockopt' on Windows is
  9161                  documented to clear the socket error for the entire
  9162                  process, which I'm not sure is TRT; FIXME.  */
  9163               if (current_status == STATUS_CONNECT_FAILED
  9164                   && (fd_info[fd].flags & FILE_CONNECT) != 0
  9165                   && cp->errcode != 0)
  9166                 {
  9167                   pfn_WSASetLastError (cp->errcode);
  9168                   set_errno ();
  9169                   return -1;
  9170                 }
  9171               /* Do the equivalent of a non-blocking read.  */
  9172               pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
  9173               if (waiting == 0 && nchars == 0)
  9174                 {
  9175                   errno = EWOULDBLOCK;
  9176                   return -1;
  9177                 }
  9178 
  9179               if (waiting)
  9180                 {
  9181                   /* always use binary mode for sockets */
  9182                   int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
  9183                   if (res == SOCKET_ERROR)
  9184                     {
  9185                       set_errno ();
  9186                       DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
  9187                                  errno, SOCK_HANDLE (fd)));
  9188                       return -1;
  9189                     }
  9190                   nchars += res;
  9191                 }
  9192             }
  9193         }
  9194       else
  9195         {
  9196           int nread = _read (fd, buffer, count);
  9197           if (nread >= 0)
  9198             nchars += nread;
  9199           else if (nchars == 0)
  9200             nchars = nread;
  9201         }
  9202 
  9203       if (nchars <= 0)
  9204         fd_info[fd].flags |= FILE_AT_EOF;
  9205       /* Perform text mode translation if required.  */
  9206       else if ((fd_info[fd].flags & FILE_BINARY) == 0)
  9207         {
  9208           nchars = crlf_to_lf (nchars, orig_buffer);
  9209           /* If buffer contains only CR, return that.  To be absolutely
  9210              sure we should attempt to read the next char, but in
  9211              practice a CR to be followed by LF would not appear by
  9212              itself in the buffer.  */
  9213           if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
  9214             {
  9215               fd_info[fd].flags |= FILE_LAST_CR;
  9216               nchars--;
  9217             }
  9218         }
  9219     }
  9220   else
  9221     nchars = _read (fd, buffer, count);
  9222 
  9223   return nchars;
  9224 }
  9225 
  9226 /* From w32xfns.c */
  9227 extern HANDLE interrupt_handle;
  9228 
  9229 int
  9230 sys_write (int fd, const void * buffer, unsigned int count)
  9231 {
  9232   int nchars;
  9233   USE_SAFE_ALLOCA;
  9234 
  9235   if (fd < 0)
  9236     {
  9237       errno = EBADF;
  9238       return -1;
  9239     }
  9240 
  9241   if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
  9242     {
  9243       if ((fd_info[fd].flags & FILE_WRITE) == 0)
  9244         {
  9245           errno = EBADF;
  9246           return -1;
  9247         }
  9248 
  9249       /* Perform text mode translation if required.  */
  9250       if ((fd_info[fd].flags & FILE_BINARY) == 0)
  9251         {
  9252           char * tmpbuf;
  9253           const unsigned char * src = buffer;
  9254           unsigned char * dst;
  9255           int nbytes = count;
  9256 
  9257           SAFE_NALLOCA (tmpbuf, 2, count);
  9258           dst = (unsigned char *)tmpbuf;
  9259 
  9260           while (1)
  9261             {
  9262               unsigned char *next;
  9263               /* Copy next line or remaining bytes.  */
  9264               next = _memccpy (dst, src, '\n', nbytes);
  9265               if (next)
  9266                 {
  9267                   /* Copied one line ending with '\n'.  */
  9268                   int copied = next - dst;
  9269                   nbytes -= copied;
  9270                   src += copied;
  9271                   /* Insert '\r' before '\n'.  */
  9272                   next[-1] = '\r';
  9273                   next[0] = '\n';
  9274                   dst = next + 1;
  9275                   count++;
  9276                 }
  9277               else
  9278                 /* Copied remaining partial line -> now finished.  */
  9279                 break;
  9280             }
  9281           buffer = tmpbuf;
  9282         }
  9283     }
  9284 
  9285   if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
  9286     {
  9287       HANDLE hnd = (HANDLE) _get_osfhandle (fd);
  9288       OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
  9289       HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
  9290       DWORD active = 0;
  9291 
  9292       /* This is async (a.k.a. "overlapped") I/O, so the return value
  9293          of FALSE from WriteFile means either an error or the output
  9294          will be completed asynchronously (ERROR_IO_PENDING).  */
  9295       if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
  9296         {
  9297           if (GetLastError () != ERROR_IO_PENDING)
  9298             {
  9299               errno = EIO;
  9300               nchars = -1;
  9301             }
  9302           else
  9303             {
  9304               /* Wait for the write to complete, and watch C-g while
  9305                  at that.  */
  9306               if (detect_input_pending ())
  9307                 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
  9308                                                     INFINITE, QS_ALLINPUT);
  9309               else
  9310                 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
  9311               switch (active)
  9312                 {
  9313                 case WAIT_OBJECT_0:
  9314                   /* User pressed C-g, cancel write, then leave.
  9315                      Don't bother cleaning up as we may only get stuck
  9316                      in buggy drivers.  */
  9317                   PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
  9318                   CancelIo (hnd);
  9319                   errno = EIO;  /* Why not EINTR? */
  9320                   nchars = -1;
  9321                   break;
  9322                 case WAIT_OBJECT_0 + 1:
  9323                   if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
  9324                     {
  9325                       errno = EIO;
  9326                       nchars = -1;
  9327                     }
  9328                   break;
  9329                 }
  9330             }
  9331         }
  9332     }
  9333   else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
  9334     {
  9335       unsigned long nblock = 0;
  9336       if (winsock_lib == NULL) emacs_abort ();
  9337 
  9338       child_process *cp = fd_info[fd].cp;
  9339 
  9340       /* If this is a non-blocking socket whose connection is in
  9341          progress or terminated with an error already, return the
  9342          proper error code to the caller. */
  9343       if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
  9344         {
  9345           /* In case connection is in progress, ENOTCONN that would
  9346              result from calling pfn_send is not what callers expect. */
  9347           if (cp->status != STATUS_CONNECT_FAILED)
  9348             {
  9349               errno = EWOULDBLOCK;
  9350               return -1;
  9351             }
  9352           /* In case connection failed, use the actual error code
  9353              stashed by '_sys_wait_connect' in cp->errcode. */
  9354           else if (cp->errcode != 0)
  9355             {
  9356               pfn_WSASetLastError (cp->errcode);
  9357               set_errno ();
  9358               return -1;
  9359             }
  9360         }
  9361 
  9362       /* TODO: implement select() properly so non-blocking I/O works. */
  9363       /* For now, make sure the write blocks.  */
  9364       if (fd_info[fd].flags & FILE_NDELAY)
  9365         pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
  9366 
  9367       nchars =  pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
  9368 
  9369       if (nchars == SOCKET_ERROR)
  9370         {
  9371           set_errno ();
  9372           DebPrint (("sys_write.send failed with error %d on socket %ld\n",
  9373                      pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
  9374         }
  9375 
  9376       /* Set the socket back to non-blocking if it was before,
  9377          for other operations that support it.  */
  9378       if (fd_info[fd].flags & FILE_NDELAY)
  9379         {
  9380           nblock = 1;
  9381           pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
  9382         }
  9383     }
  9384   else
  9385     {
  9386       /* Some networked filesystems don't like too large writes, so
  9387          break them into smaller chunks.  See the Comments section of
  9388          the MSDN documentation of WriteFile for details behind the
  9389          choice of the value of CHUNK below.  See also the thread
  9390          http://thread.gmane.org/gmane.comp.version-control.git/145294
  9391          in the git mailing list.  */
  9392       const unsigned char *p = buffer;
  9393       const bool is_pipe = (fd < MAXDESC
  9394                             && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
  9395                                 == (FILE_PIPE | FILE_NDELAY)));
  9396       /* Some programs, notably Node.js's node.exe, seem to never
  9397          completely empty the pipe, so writing more than the size of
  9398          the pipe's buffer always returns ENOSPC, and we loop forever
  9399          between send_process and here.  As a workaround, write no
  9400          more than the pipe's buffer can hold.  */
  9401       DWORD pipe_buffer_size;
  9402       if (is_pipe)
  9403         {
  9404           if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
  9405                                 NULL, &pipe_buffer_size, NULL, NULL))
  9406             {
  9407               DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
  9408               pipe_buffer_size = 4096;
  9409             }
  9410         }
  9411       const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
  9412 
  9413       nchars = 0;
  9414       errno = 0;
  9415       while (count > 0)
  9416         {
  9417           unsigned this_chunk = count < chunk ? count : chunk;
  9418           int n = _write (fd, p, this_chunk);
  9419 
  9420           if (n > 0)
  9421             nchars += n;
  9422           if (n < 0)
  9423             {
  9424               /* When there's no buffer space in a pipe that is in the
  9425                  non-blocking mode, _write returns ENOSPC.  We return
  9426                  EAGAIN instead, which should trigger the logic in
  9427                  send_process that enters waiting loop and calls
  9428                  wait_reading_process_output to allow process input to
  9429                  be accepted during the wait.  Those calls to
  9430                  wait_reading_process_output allow sys_select to
  9431                  notice when process input becomes available, thus
  9432                  avoiding deadlock whereby each side of the pipe is
  9433                  blocked on write, waiting for the other party to read
  9434                  its end of the pipe.  */
  9435               if (errno == ENOSPC && is_pipe)
  9436                 errno = EAGAIN;
  9437               if (nchars == 0)
  9438                 nchars = -1;
  9439               break;
  9440             }
  9441           else if (n < this_chunk)
  9442             break;
  9443           count -= n;
  9444           p += n;
  9445         }
  9446     }
  9447 
  9448   SAFE_FREE ();
  9449   return nchars;
  9450 }
  9451 
  9452 
  9453 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c.  */
  9454 
  9455 /* Return information about network interface IFNAME, or about all
  9456    interfaces (if IFNAME is nil).  */
  9457 static Lisp_Object
  9458 network_interface_get_info (Lisp_Object ifname)
  9459 {
  9460   ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
  9461   IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
  9462   DWORD retval = get_adapters_info (ainfo, &ainfo_len);
  9463   Lisp_Object res = Qnil;
  9464 
  9465   if (retval == ERROR_BUFFER_OVERFLOW)
  9466     {
  9467       ainfo = xrealloc (ainfo, ainfo_len);
  9468       retval = get_adapters_info (ainfo, &ainfo_len);
  9469     }
  9470 
  9471   if (retval == ERROR_SUCCESS)
  9472     {
  9473       int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
  9474       int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
  9475       int if_num;
  9476       struct sockaddr_in sa;
  9477 
  9478       /* For the below, we need some winsock functions, so make sure
  9479          the winsock DLL is loaded.  If we cannot successfully load
  9480          it, they will have no use of the information we provide,
  9481          anyway, so punt.  */
  9482       if (!winsock_lib && !init_winsock (1))
  9483         goto done;
  9484 
  9485       for (adapter = ainfo; adapter; adapter = adapter->Next)
  9486         {
  9487           char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
  9488           u_long ip_addr;
  9489           /* Present Unix-compatible interface names, instead of the
  9490              Windows names, which are really GUIDs not readable by
  9491              humans.  */
  9492           static const char *ifmt[] = {
  9493             "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
  9494             "lo", "ifx%d"
  9495           };
  9496           enum {
  9497             NONE = -1,
  9498             ETHERNET = 0,
  9499             TOKENRING = 1,
  9500             FDDI = 2,
  9501             PPP = 3,
  9502             SLIP = 4,
  9503             WLAN = 5,
  9504             LOOPBACK = 6,
  9505             OTHER_IF = 7
  9506           } ifmt_idx;
  9507 
  9508           switch (adapter->Type)
  9509             {
  9510             case MIB_IF_TYPE_ETHERNET:
  9511               /* Windows before Vista reports wireless adapters as
  9512                  Ethernet.  Work around by looking at the Description
  9513                  string.  */
  9514               if (strstr (adapter->Description, "Wireless "))
  9515                 {
  9516                   ifmt_idx = WLAN;
  9517                   if_num = wlan_count++;
  9518                 }
  9519               else
  9520                 {
  9521                   ifmt_idx = ETHERNET;
  9522                   if_num = eth_count++;
  9523                 }
  9524               break;
  9525             case MIB_IF_TYPE_TOKENRING:
  9526               ifmt_idx = TOKENRING;
  9527               if_num = tr_count++;
  9528               break;
  9529             case MIB_IF_TYPE_FDDI:
  9530               ifmt_idx = FDDI;
  9531               if_num = fddi_count++;
  9532               break;
  9533             case MIB_IF_TYPE_PPP:
  9534               ifmt_idx = PPP;
  9535               if_num = ppp_count++;
  9536               break;
  9537             case MIB_IF_TYPE_SLIP:
  9538               ifmt_idx = SLIP;
  9539               if_num = sl_count++;
  9540               break;
  9541             case IF_TYPE_IEEE80211:
  9542               ifmt_idx = WLAN;
  9543               if_num = wlan_count++;
  9544               break;
  9545             case MIB_IF_TYPE_LOOPBACK:
  9546               if (lo_count < 0)
  9547                 {
  9548                   ifmt_idx = LOOPBACK;
  9549                   if_num = lo_count++;
  9550                 }
  9551               else
  9552                 ifmt_idx = NONE;
  9553               break;
  9554             default:
  9555               ifmt_idx = OTHER_IF;
  9556               if_num = ifx_count++;
  9557               break;
  9558             }
  9559           if (ifmt_idx == NONE)
  9560             continue;
  9561           sprintf (namebuf, ifmt[ifmt_idx], if_num);
  9562 
  9563           sa.sin_family = AF_INET;
  9564           ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
  9565           if (ip_addr == INADDR_NONE)
  9566             {
  9567               /* Bogus address, skip this interface.  */
  9568               continue;
  9569             }
  9570           sa.sin_addr.s_addr = ip_addr;
  9571           sa.sin_port = 0;
  9572           if (NILP (ifname))
  9573             res = Fcons (Fcons (build_string (namebuf),
  9574                                 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
  9575                                                        sizeof (struct sockaddr))),
  9576                          res);
  9577           else if (strcmp (namebuf, SSDATA (ifname)) == 0)
  9578             {
  9579               Lisp_Object hwaddr = Fmake_vector (make_fixnum (6), Qnil);
  9580               register struct Lisp_Vector *p = XVECTOR (hwaddr);
  9581               Lisp_Object flags = Qnil;
  9582               int n;
  9583               u_long net_mask;
  9584 
  9585               /* Flags.  We guess most of them by type, since the
  9586                  Windows flags are different and hard to get by.  */
  9587               flags = Fcons (intern ("up"), flags);
  9588               if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
  9589                 {
  9590                   flags = Fcons (intern ("broadcast"), flags);
  9591                   flags = Fcons (intern ("multicast"), flags);
  9592                 }
  9593               flags = Fcons (intern ("running"), flags);
  9594               if (ifmt_idx == PPP)
  9595                 {
  9596                   flags = Fcons (intern ("pointopoint"), flags);
  9597                   flags = Fcons (intern ("noarp"), flags);
  9598                 }
  9599               if (adapter->HaveWins)
  9600                 flags = Fcons (intern ("WINS"), flags);
  9601               if (adapter->DhcpEnabled)
  9602                 flags = Fcons (intern ("dynamic"), flags);
  9603 
  9604               res = Fcons (flags, res);
  9605 
  9606               /* Hardware address and its family.  */
  9607               for (n = 0; n < adapter->AddressLength; n++)
  9608                 p->contents[n] = make_fixnum ((int) adapter->Address[n]);
  9609               /* Windows does not support AF_LINK or AF_PACKET family
  9610                  of addresses.  Use an arbitrary family number that is
  9611                  identical to what GNU/Linux returns.  */
  9612               res = Fcons (Fcons (make_fixnum (1), hwaddr), res);
  9613 
  9614               /* Network mask.  */
  9615               sa.sin_family = AF_INET;
  9616               net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
  9617               if (net_mask != INADDR_NONE)
  9618                 {
  9619                   sa.sin_addr.s_addr = net_mask;
  9620                   sa.sin_port = 0;
  9621                   res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9622                                                       sizeof (struct sockaddr)),
  9623                                res);
  9624                 }
  9625               else
  9626                 res = Fcons (Qnil, res);
  9627 
  9628               sa.sin_family = AF_INET;
  9629               if (ip_addr != INADDR_NONE)
  9630                 {
  9631                   /* Broadcast address is only reported by
  9632                      GetAdaptersAddresses, which is of limited
  9633                      availability.  Generate it on our own.  */
  9634                   u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
  9635 
  9636                   sa.sin_addr.s_addr = bcast_addr;
  9637                   sa.sin_port = 0;
  9638                   res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9639                                                       sizeof (struct sockaddr)),
  9640                                res);
  9641 
  9642                   /* IP address.  */
  9643                   sa.sin_addr.s_addr = ip_addr;
  9644                   sa.sin_port = 0;
  9645                   res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9646                                                       sizeof (struct sockaddr)),
  9647                                res);
  9648                 }
  9649               else
  9650                 res = Fcons (Qnil, Fcons (Qnil, res));
  9651             }
  9652         }
  9653       /* GetAdaptersInfo is documented to not report loopback
  9654          interfaces, so we generate one out of thin air.  */
  9655       if (!lo_count)
  9656         {
  9657           sa.sin_family = AF_INET;
  9658           sa.sin_port = 0;
  9659           if (NILP (ifname))
  9660             {
  9661               sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
  9662               res = Fcons (Fcons (build_string ("lo"),
  9663                                   conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
  9664                                                          sizeof (struct sockaddr))),
  9665                            res);
  9666             }
  9667           else if (strcmp (SSDATA (ifname), "lo") == 0)
  9668             {
  9669               res = Fcons (Fcons (intern ("running"),
  9670                                   Fcons (intern ("loopback"),
  9671                                          Fcons (intern ("up"), Qnil))), Qnil);
  9672               /* 772 is what 3 different GNU/Linux systems report for
  9673                  the loopback interface.  */
  9674               res = Fcons (Fcons (make_fixnum (772),
  9675                                   Fmake_vector (make_fixnum (6),
  9676                                                 make_fixnum (0))),
  9677                            res);
  9678               sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
  9679               res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9680                                                   sizeof (struct sockaddr)),
  9681                            res);
  9682               sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
  9683               res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9684                                                   sizeof (struct sockaddr)),
  9685                            res);
  9686               sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
  9687               res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
  9688                                                   sizeof (struct sockaddr)),
  9689                            res);
  9690             }
  9691 
  9692         }
  9693     }
  9694 
  9695  done:
  9696   xfree (ainfo);
  9697   return res;
  9698 }
  9699 
  9700 static bool
  9701 address_prefix_match (int family, struct sockaddr *address,
  9702                       struct sockaddr *prefix_address, ULONG prefix_len)
  9703 {
  9704   UINT8 *address_data;
  9705   UINT8 *prefix_address_data;
  9706   int i;
  9707 
  9708   if (family == AF_INET6)
  9709     {
  9710       address_data = (UINT8 *) &(((struct sockaddr_in6 *) address)->sin6_addr);
  9711       prefix_address_data =
  9712         (UINT8 *) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
  9713     }
  9714   else
  9715     {
  9716       address_data = (UINT8 *) &(((struct sockaddr_in *) address)->sin_addr);
  9717       prefix_address_data =
  9718         (UINT8 *) &(((struct sockaddr_in *) prefix_address)->sin_addr);
  9719     }
  9720 
  9721   for (i = 0; i < prefix_len >> 3; i++)
  9722     {
  9723       if (address_data[i] != prefix_address_data[i])
  9724         return false;
  9725     }
  9726 
  9727   if (prefix_len % 8)
  9728     return (prefix_address_data[i] ==
  9729             (address_data[i] & (0xff << (8 - prefix_len % 8))));
  9730 
  9731   return true;
  9732 }
  9733 
  9734 Lisp_Object
  9735 network_interface_list (bool full, unsigned short match)
  9736 {
  9737   ULONG ainfo_len = sizeof (IP_ADAPTER_ADDRESSES);
  9738   ULONG family = match;
  9739   IP_ADAPTER_ADDRESSES *adapter, *ainfo = xmalloc (ainfo_len);
  9740   DWORD retval = get_adapters_addresses (family, ainfo, &ainfo_len);
  9741   Lisp_Object res = Qnil;
  9742 
  9743   if (retval == ERROR_BUFFER_OVERFLOW)
  9744     {
  9745       ainfo = xrealloc (ainfo, ainfo_len);
  9746       retval = get_adapters_addresses (family, ainfo, &ainfo_len);
  9747     }
  9748 
  9749   if (retval != ERROR_SUCCESS)
  9750     {
  9751       xfree (ainfo);
  9752       return res;
  9753     }
  9754 
  9755   /* For the below, we need some winsock functions, so make sure
  9756      the winsock DLL is loaded.  If we cannot successfully load
  9757      it, they will have no use of the information we provide,
  9758      anyway, so punt.  */
  9759   if (!winsock_lib && !init_winsock (1))
  9760     return res;
  9761 
  9762   int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
  9763   int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
  9764   int tnl_count = 0;
  9765   int if_num;
  9766   char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
  9767   static const char *ifmt[] = {
  9768     "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
  9769     "lo%d", "ifx%d", "tunnel%d"
  9770   };
  9771   enum {
  9772     NONE = -1,
  9773     ETHERNET = 0,
  9774     TOKENRING = 1,
  9775     FDDI = 2,
  9776     PPP = 3,
  9777     SLIP = 4,
  9778     WLAN = 5,
  9779     LOOPBACK = 6,
  9780     OTHER_IF = 7,
  9781     TUNNEL = 8
  9782   } ifmt_idx;
  9783 
  9784   for (adapter = ainfo; adapter; adapter = adapter->Next)
  9785     {
  9786 
  9787       /* Present Unix-compatible interface names, instead of the
  9788          Windows names, which are really GUIDs not readable by
  9789          humans.  */
  9790 
  9791       switch (adapter->IfType)
  9792         {
  9793         case IF_TYPE_ETHERNET_CSMACD:
  9794           /* Windows before Vista reports wireless adapters as
  9795              Ethernet.  Work around by looking at the Description
  9796              string.  */
  9797           {
  9798           char description[MAX_UTF8_PATH];
  9799           if (filename_from_utf16 (adapter->Description, description) == 0
  9800               && strstr (description, "Wireless "))
  9801             {
  9802               ifmt_idx = WLAN;
  9803               if_num = wlan_count++;
  9804             }
  9805           else
  9806             {
  9807               ifmt_idx = ETHERNET;
  9808               if_num = eth_count++;
  9809             }
  9810           }
  9811           break;
  9812         case IF_TYPE_ISO88025_TOKENRING:
  9813           ifmt_idx = TOKENRING;
  9814           if_num = tr_count++;
  9815           break;
  9816         case IF_TYPE_FDDI:
  9817           ifmt_idx = FDDI;
  9818           if_num = fddi_count++;
  9819           break;
  9820         case IF_TYPE_PPP:
  9821           ifmt_idx = PPP;
  9822           if_num = ppp_count++;
  9823           break;
  9824         case IF_TYPE_SLIP:
  9825           ifmt_idx = SLIP;
  9826           if_num = sl_count++;
  9827           break;
  9828         case IF_TYPE_IEEE80211:
  9829           ifmt_idx = WLAN;
  9830           if_num = wlan_count++;
  9831           break;
  9832         case IF_TYPE_SOFTWARE_LOOPBACK:
  9833           ifmt_idx = LOOPBACK;
  9834           if_num = lo_count++;
  9835           break;
  9836         case IF_TYPE_TUNNEL:
  9837           ifmt_idx = TUNNEL;
  9838           if_num = tnl_count++;
  9839           break;
  9840         default:
  9841           ifmt_idx = OTHER_IF;
  9842           if_num = ifx_count++;
  9843           break;
  9844         }
  9845       sprintf (namebuf, ifmt[ifmt_idx], if_num);
  9846 
  9847       IP_ADAPTER_UNICAST_ADDRESS *address;
  9848       for (address = adapter->FirstUnicastAddress; address; address = address->Next)
  9849         {
  9850           int len;
  9851           int addr_len;
  9852           uint32_t *maskp;
  9853           uint32_t *addrp;
  9854           Lisp_Object elt = Qnil;
  9855           struct sockaddr *ifa_addr = address->Address.lpSockaddr;
  9856 
  9857           if (ifa_addr == NULL)
  9858             continue;
  9859           if (match && ifa_addr->sa_family != match)
  9860             continue;
  9861 
  9862           struct sockaddr_in ipv4;
  9863 #ifdef AF_INET6
  9864           struct sockaddr_in6 ipv6;
  9865 #endif
  9866           struct sockaddr *sin;
  9867 
  9868           if (ifa_addr->sa_family == AF_INET)
  9869             {
  9870               ipv4.sin_family = AF_INET;
  9871               ipv4.sin_port = 0;
  9872               DECLARE_POINTER_ALIAS (sin_in, struct sockaddr_in, ifa_addr);
  9873               addrp = (uint32_t *)&sin_in->sin_addr;
  9874               maskp = (uint32_t *)&ipv4.sin_addr;
  9875               sin = (struct sockaddr *)&ipv4;
  9876               len = sizeof (struct sockaddr_in);
  9877               addr_len = 1;
  9878             }
  9879 #ifdef AF_INET6
  9880           else if (ifa_addr->sa_family == AF_INET6)
  9881             {
  9882               ipv6.sin6_family = AF_INET6;
  9883               ipv6.sin6_port = 0;
  9884               DECLARE_POINTER_ALIAS (sin_in6, struct sockaddr_in6, ifa_addr);
  9885               addrp = (uint32_t *)&sin_in6->sin6_addr;
  9886               maskp = (uint32_t *)&ipv6.sin6_addr;
  9887               sin = (struct sockaddr *)&ipv6;
  9888               len = sizeof (struct sockaddr_in6);
  9889               addr_len = 4;
  9890             }
  9891 #endif
  9892           else
  9893             continue;
  9894 
  9895           Lisp_Object addr = conv_sockaddr_to_lisp (ifa_addr, len);
  9896 
  9897           if (full)
  9898             {
  9899               /* GetAdaptersAddress returns information in network
  9900                  byte order, so convert from host to network order
  9901                  when generating the netmask.  */
  9902               int i;
  9903               ULONG numbits;
  9904               if (w32_major_version >= 6) /* Vista or later */
  9905                 {
  9906 #if _WIN32_WINNT >= 0x0600
  9907                   numbits = address->OnLinkPrefixLength;
  9908 #else
  9909                   /* Kludge alert!  OnLinkPrefixLength is only defined
  9910                      when compiling for Vista and later.  */
  9911                   numbits = *(UINT8 *) (&address->LeaseLifetime + 1);
  9912 #endif
  9913                 }
  9914               else              /* Windows XP */
  9915                 {
  9916                   IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix;
  9917                   numbits = 0;
  9918                   for ( ; prefix; prefix = prefix->Next)
  9919                     {
  9920                       /* We want the longest matching prefix.  */
  9921                       if ((prefix->Address.lpSockaddr->sa_family
  9922                            == ifa_addr->sa_family)
  9923                           && (prefix->PrefixLength > numbits)
  9924                           && address_prefix_match (ifa_addr->sa_family,
  9925                                                    ifa_addr,
  9926                                                    prefix->Address.lpSockaddr,
  9927                                                    prefix->PrefixLength))
  9928                         numbits = prefix->PrefixLength;
  9929                     }
  9930                   if (!numbits)
  9931                     numbits = (ifa_addr->sa_family == AF_INET6) ? 128 : 32;
  9932                 }
  9933               for (i = 0; i < addr_len; i++)
  9934                 {
  9935                   if (numbits >= 32)
  9936                     {
  9937                       maskp[i] = -1U;
  9938                       numbits -= 32;
  9939                     }
  9940                   else if (numbits)
  9941                     {
  9942                       maskp[i] = sys_htonl (-1U << (32 - numbits));
  9943                       numbits = 0;
  9944                     }
  9945                   else
  9946                     {
  9947                       maskp[i] = 0;
  9948                     }
  9949                 }
  9950               elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
  9951               uint32_t mask;
  9952               for (i = 0; i < addr_len; i++)
  9953                 {
  9954                   mask = maskp[i];
  9955                   maskp[i] = (addrp[i] & mask) | ~mask;
  9956 
  9957                 }
  9958               elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt);
  9959               elt = Fcons (addr, elt);
  9960             }
  9961           else
  9962             {
  9963               elt = addr;
  9964             }
  9965           res = Fcons (Fcons (build_string (namebuf), elt), res);
  9966         }
  9967     }
  9968   xfree (ainfo);
  9969   return res;
  9970 }
  9971 
  9972 Lisp_Object
  9973 network_interface_info (Lisp_Object ifname)
  9974 {
  9975   CHECK_STRING (ifname);
  9976   return network_interface_get_info (ifname);
  9977 }
  9978 
  9979 
  9980 /* Workhorse for w32-read-registry, which see.  */
  9981 Lisp_Object
  9982 w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
  9983 {
  9984   HKEY hkey = NULL;
  9985   LONG status;
  9986   DWORD vsize, vtype;
  9987   LPBYTE pvalue;
  9988   Lisp_Object val, retval;
  9989   const char *key, *value_name = NULL;
  9990   /* The following sizes are according to size limitations
  9991      documented in MSDN.  */
  9992   wchar_t key_w[255+1];
  9993   wchar_t value_w[16*1024+1];
  9994   bool use_unicode = is_windows_9x () == 0;
  9995 
  9996   if (use_unicode)
  9997     {
  9998       Lisp_Object encoded_key, encoded_vname;
  9999 
 10000       /* Convert input strings to UTF-16.  */
 10001       encoded_key = code_convert_string_norecord (lkey, Qutf_16le, 1);
 10002       memcpy (key_w, SSDATA (encoded_key), SBYTES (encoded_key));
 10003       /* wchar_t strings need to be terminated by 2 null bytes.  */
 10004       key_w [SBYTES (encoded_key)/2] = L'\0';
 10005       encoded_vname = code_convert_string_norecord (lname, Qutf_16le, 1);
 10006       memcpy (value_w, SSDATA (encoded_vname), SBYTES (encoded_vname));
 10007       value_w[SBYTES (encoded_vname)/2] = L'\0';
 10008 
 10009       /* Mirror the slashes, if required.  */
 10010       for (int i = 0; i < SBYTES (encoded_key)/2; i++)
 10011         {
 10012           if (key_w[i] == L'/')
 10013             key_w[i] = L'\\';
 10014         }
 10015       if ((status = reg_open_key_ex_w (rootkey, key_w, 0,
 10016                                        KEY_READ, &hkey)) == ERROR_NOT_SUPPORTED
 10017           || (status = reg_query_value_ex_w (hkey, value_w, NULL, NULL, NULL,
 10018                                              &vsize)) == ERROR_NOT_SUPPORTED
 10019           || status != ERROR_SUCCESS)
 10020         {
 10021           if (hkey)
 10022             RegCloseKey (hkey);
 10023           if (status != ERROR_NOT_SUPPORTED)
 10024             return Qnil;
 10025           use_unicode = 0;      /* fall back to non-Unicode calls */
 10026         }
 10027     }
 10028   if (!use_unicode)
 10029     {
 10030       /* Need to copy LKEY because we are going to modify it.  */
 10031       Lisp_Object local_lkey = Fcopy_sequence (lkey);
 10032 
 10033       /* Mirror the slashes.  Note: this has to be done before
 10034          encoding, because after encoding we cannot guarantee that a
 10035          slash '/' always stands for itself, it could be part of some
 10036          multibyte sequence.  */
 10037       for (int i = 0; i < SBYTES (local_lkey); i++)
 10038         {
 10039           if (SSDATA (local_lkey)[i] == '/')
 10040             SSDATA (local_lkey)[i] = '\\';
 10041         }
 10042 
 10043       key = SSDATA (ENCODE_SYSTEM (local_lkey));
 10044       value_name = SSDATA (ENCODE_SYSTEM (lname));
 10045 
 10046       if ((status = RegOpenKeyEx (rootkey, key, 0,
 10047                                   KEY_READ, &hkey)) != ERROR_SUCCESS
 10048           || (status = RegQueryValueEx (hkey, value_name, NULL,
 10049                                         NULL, NULL, &vsize)) != ERROR_SUCCESS)
 10050         {
 10051           if (hkey)
 10052             RegCloseKey (hkey);
 10053           return Qnil;
 10054         }
 10055     }
 10056 
 10057   pvalue = xzalloc (vsize);
 10058   if (use_unicode)
 10059     status = reg_query_value_ex_w (hkey, value_w, NULL, &vtype, pvalue, &vsize);
 10060   else
 10061     status = RegQueryValueEx (hkey, value_name, NULL, &vtype, pvalue, &vsize);
 10062   if (status != ERROR_SUCCESS)
 10063     {
 10064       xfree (pvalue);
 10065       RegCloseKey (hkey);
 10066       return Qnil;
 10067     }
 10068 
 10069   switch (vtype)
 10070     {
 10071       case REG_NONE:
 10072         retval = Qt;
 10073         break;
 10074       case REG_DWORD:
 10075         retval = INT_TO_INTEGER (*((DWORD *)pvalue));
 10076         break;
 10077       case REG_QWORD:
 10078         retval = INT_TO_INTEGER (*((long long *)pvalue));
 10079         break;
 10080       case REG_BINARY:
 10081         {
 10082           int i;
 10083           unsigned char *dbuf = (unsigned char *)pvalue;
 10084 
 10085           val = make_uninit_vector (vsize);
 10086           for (i = 0; i < vsize; i++)
 10087             ASET (val, i, make_fixnum (dbuf[i]));
 10088 
 10089           retval = val;
 10090           break;
 10091         }
 10092       case REG_SZ:
 10093         if (use_unicode)
 10094           {
 10095             /* pvalue ends with 2 null bytes, but we need only one,
 10096                and AUTO_STRING_WITH_LEN will add it.  */
 10097             if (pvalue[vsize - 1] == '\0')
 10098               vsize -= 2;
 10099             AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
 10100             retval = from_unicode (sval);
 10101           }
 10102         else
 10103           {
 10104             /* Don't waste a byte on the terminating null character,
 10105                since make_unibyte_string will add one anyway.  */
 10106             if (pvalue[vsize - 1] == '\0')
 10107               vsize--;
 10108             retval = DECODE_SYSTEM (make_unibyte_string (pvalue, vsize));
 10109           }
 10110         break;
 10111       case REG_EXPAND_SZ:
 10112         if (use_unicode)
 10113           {
 10114             wchar_t expanded_w[32*1024];
 10115             DWORD dsize = sizeof (expanded_w) / 2;
 10116             DWORD produced = expand_environment_strings_w ((wchar_t *)pvalue,
 10117                                                            expanded_w,
 10118                                                            dsize);
 10119             if (produced > 0 && produced < dsize)
 10120               {
 10121                 AUTO_STRING_WITH_LEN (sval, (char *)expanded_w,
 10122                                       produced * 2 - 2);
 10123                 retval = from_unicode (sval);
 10124               }
 10125             else
 10126               {
 10127                 if (pvalue[vsize - 1] == '\0')
 10128                   vsize -= 2;
 10129                 AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
 10130                 retval = from_unicode (sval);
 10131               }
 10132           }
 10133         else
 10134           {
 10135             char expanded[32*1024]; /* size limitation according to MSDN */
 10136             DWORD produced = ExpandEnvironmentStrings ((char *)pvalue,
 10137                                                        expanded,
 10138                                                        sizeof (expanded));
 10139             if (produced > 0 && produced < sizeof (expanded))
 10140               retval = make_unibyte_string (expanded, produced - 1);
 10141             else
 10142               {
 10143                 if (pvalue[vsize - 1] == '\0')
 10144                   vsize--;
 10145                 retval = make_unibyte_string (pvalue, vsize);
 10146               }
 10147 
 10148             retval = DECODE_SYSTEM (retval);
 10149           }
 10150         break;
 10151       case REG_MULTI_SZ:
 10152         if (use_unicode)
 10153           {
 10154             wchar_t *wp = (wchar_t *)pvalue;
 10155 
 10156             val = Qnil;
 10157             do {
 10158               size_t wslen = wcslen (wp);
 10159               AUTO_STRING_WITH_LEN (sval, (char *)wp, wslen * 2);
 10160               val = Fcons (from_unicode (sval), val);
 10161               wp += wslen + 1;
 10162             } while (*wp);
 10163           }
 10164         else
 10165           {
 10166             char *p = (char *)pvalue;
 10167 
 10168             val = Qnil;
 10169             do {
 10170               size_t slen = strlen (p);
 10171 
 10172               val = Fcons (DECODE_SYSTEM (make_unibyte_string (p, slen)), val);
 10173               p += slen + 1;
 10174             } while (*p);
 10175           }
 10176 
 10177         retval = Fnreverse (val);
 10178         break;
 10179       default:
 10180         error ("unsupported registry data type: %d", (int)vtype);
 10181     }
 10182 
 10183   xfree (pvalue);
 10184   RegCloseKey (hkey);
 10185   return retval;
 10186 }
 10187 
 10188 
 10189 /* The Windows CRT functions are "optimized for speed", so they don't
 10190    check for timezone and DST changes if they were last called less
 10191    than 1 minute ago (see http://support.microsoft.com/kb/821231).  So
 10192    all Emacs features that repeatedly call time functions (e.g.,
 10193    display-time) are in real danger of missing timezone and DST
 10194    changes.  Calling tzset before each localtime call fixes that.  */
 10195 struct tm *
 10196 sys_localtime (const time_t *t)
 10197 {
 10198   tzset ();
 10199   return localtime (t);
 10200 }
 10201 
 10202 /* The Windows CRT implementation of 'clock' doesn't really return CPU
 10203    time of the process (it returns the elapsed time since the process
 10204    started), so we provide a better emulation here, if possible.  */
 10205 clock_t
 10206 sys_clock (void)
 10207 {
 10208   if (get_process_times_fn)
 10209     {
 10210       FILETIME create, exit, kernel, user;
 10211       HANDLE proc = GetCurrentProcess ();
 10212       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
 10213         {
 10214           LARGE_INTEGER user_int, kernel_int, total;
 10215           user_int.LowPart = user.dwLowDateTime;
 10216           user_int.HighPart = user.dwHighDateTime;
 10217           kernel_int.LowPart = kernel.dwLowDateTime;
 10218           kernel_int.HighPart = kernel.dwHighDateTime;
 10219           total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
 10220           /* We could redefine CLOCKS_PER_SEC to provide a finer
 10221              resolution, but with the basic 15.625 msec resolution of
 10222              the Windows clock, it doesn't really sound worth the hassle.  */
 10223           return total.QuadPart / (10000000 / CLOCKS_PER_SEC);
 10224         }
 10225     }
 10226   return clock ();
 10227 }
 10228 
 10229 
 10230 /* Try loading LIBRARY_ID from the file(s) specified in
 10231    Vdynamic_library_alist.  If the library is loaded successfully,
 10232    return the handle of the DLL, and record the filename in the
 10233    property :loaded-from of LIBRARY_ID.  If the library could not be
 10234    found, or when it was already loaded (because the handle is not
 10235    recorded anywhere, and so is lost after use), return NULL.
 10236 
 10237    We could also save the handle in :loaded-from, but currently
 10238    there's no use case for it.  */
 10239 HMODULE
 10240 w32_delayed_load (Lisp_Object library_id)
 10241 {
 10242   HMODULE dll_handle = NULL;
 10243 
 10244   CHECK_SYMBOL (library_id);
 10245 
 10246   if (CONSP (Vdynamic_library_alist)
 10247       && NILP (Fassq (library_id, Vlibrary_cache)))
 10248     {
 10249       Lisp_Object found = Qnil;
 10250       Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
 10251 
 10252       if (CONSP (dlls))
 10253         for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
 10254           {
 10255             Lisp_Object dll = XCAR (dlls);
 10256             char name[MAX_UTF8_PATH];
 10257             DWORD res = -1;
 10258 
 10259             CHECK_STRING (dll);
 10260             dll = ENCODE_FILE (dll);
 10261             if (w32_unicode_filenames)
 10262               {
 10263                 wchar_t name_w[MAX_PATH];
 10264 
 10265                 filename_to_utf16 (SSDATA (dll), name_w);
 10266                 dll_handle = LoadLibraryW (name_w);
 10267                 if (dll_handle)
 10268                   {
 10269                     res = GetModuleFileNameW (dll_handle, name_w,
 10270                                               sizeof (name_w));
 10271                     if (res > 0)
 10272                       filename_from_utf16 (name_w, name);
 10273                   }
 10274               }
 10275             else
 10276               {
 10277                 char name_a[MAX_PATH];
 10278 
 10279                 filename_to_ansi (SSDATA (dll), name_a);
 10280                 dll_handle = LoadLibraryA (name_a);
 10281                 if (dll_handle)
 10282                   {
 10283                     res = GetModuleFileNameA (dll_handle, name_a,
 10284                                               sizeof (name_a));
 10285                     if (res > 0)
 10286                       filename_from_ansi (name_a, name);
 10287                   }
 10288               }
 10289             if (dll_handle)
 10290               {
 10291                 ptrdiff_t len = strlen (name);
 10292                 found = Fcons (dll,
 10293                                (res > 0)
 10294                                /* Possibly truncated */
 10295                                ? make_specified_string (name, -1, len, 1)
 10296                                : Qnil);
 10297                 /* This prevents thread start and end notifications
 10298                    from being sent to the DLL, for every thread we
 10299                    start.  We don't need those notifications because
 10300                    threads we create never use any of these DLLs, only
 10301                    the main thread uses them.  This is supposed to
 10302                    speed up thread creation.  */
 10303                 DisableThreadLibraryCalls (dll_handle);
 10304                 break;
 10305               }
 10306           }
 10307 
 10308       Fput (library_id, QCloaded_from, found);
 10309     }
 10310 
 10311   return dll_handle;
 10312 }
 10313 
 10314 
 10315 void
 10316 check_windows_init_file (void)
 10317 {
 10318   /* A common indication that Emacs is not installed properly is when
 10319      it cannot find the Windows installation file.  If this file does
 10320      not exist in the expected place, tell the user.  */
 10321 
 10322   if (!noninteractive && !inhibit_window_system
 10323       /* Vload_path is not yet initialized when we are loading
 10324          loadup.el.  */
 10325       && NILP (Vpurify_flag))
 10326     {
 10327       Lisp_Object init_file;
 10328       int fd;
 10329 
 10330       /* Implementation note: this function runs early during Emacs
 10331          startup, before startup.el is run.  So Vload_path is still in
 10332          its initial unibyte form, but it holds UTF-8 encoded file
 10333          names, since init_callproc was already called.  So we do not
 10334          need to ENCODE_FILE here, but we do need to convert the file
 10335          names from UTF-8 to ANSI.  */
 10336       init_file = build_string ("term/w32-win");
 10337       fd =
 10338         openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0, 0,
 10339                NULL);
 10340       if (fd < 0)
 10341         {
 10342           Lisp_Object load_path_print = Fprin1_to_string (Vload_path,
 10343                                                           Qnil, Qnil);
 10344           char *init_file_name = SSDATA (init_file);
 10345           char *load_path = SSDATA (load_path_print);
 10346           char *buffer = alloca (1024
 10347                                  + strlen (init_file_name)
 10348                                  + strlen (load_path));
 10349           char *msg = buffer;
 10350           int needed;
 10351 
 10352           sprintf (buffer,
 10353                    "The Emacs Windows initialization file \"%s.el\" "
 10354                    "could not be found in your Emacs installation.  "
 10355                    "Emacs checked the following directories for this file:\n"
 10356                    "\n%s\n\n"
 10357                    "When Emacs cannot find this file, it usually means that it "
 10358                    "was not installed properly, or its distribution file was "
 10359                    "not unpacked properly.\nSee the README.W32 file in the "
 10360                    "top-level Emacs directory for more information.",
 10361                    init_file_name, load_path);
 10362           needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 10363                                          buffer, -1, NULL, 0);
 10364           if (needed > 0)
 10365             {
 10366               wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
 10367 
 10368               pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
 10369                                     -1, msg_w, needed);
 10370               needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
 10371                                              NULL, 0, NULL, NULL);
 10372               if (needed > 0)
 10373                 {
 10374                   char *msg_a = alloca (needed + 1);
 10375 
 10376                   pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
 10377                                         NULL, NULL);
 10378                   msg = msg_a;
 10379                 }
 10380             }
 10381           MessageBox (NULL,
 10382                       msg,
 10383                       "Emacs Abort Dialog",
 10384                       MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
 10385           /* Use the low-level system abort. */
 10386           abort ();
 10387         }
 10388       else
 10389         {
 10390           _close (fd);
 10391         }
 10392     }
 10393 }
 10394 
 10395 void
 10396 term_ntproc (int ignored)
 10397 {
 10398   (void)ignored;
 10399 
 10400   term_timers ();
 10401 
 10402   /* shutdown the socket interface if necessary */
 10403   term_winsock ();
 10404 
 10405   term_w32select ();
 10406 
 10407 #if HAVE_NATIVE_IMAGE_API
 10408   w32_gdiplus_shutdown ();
 10409 #endif
 10410 }
 10411 
 10412 void
 10413 init_ntproc (int dumping)
 10414 {
 10415   sigset_t initial_mask = 0;
 10416 
 10417   /* Initialize the socket interface now if available and requested by
 10418      the user by defining PRELOAD_WINSOCK; otherwise loading will be
 10419      delayed until open-network-stream is called (w32-has-winsock can
 10420      also be used to dynamically load or reload winsock).
 10421 
 10422      Conveniently, init_environment is called before us, so
 10423      PRELOAD_WINSOCK can be set in the registry. */
 10424 
 10425   /* Always initialize this correctly. */
 10426   winsock_lib = NULL;
 10427 
 10428   if (getenv ("PRELOAD_WINSOCK") != NULL)
 10429     init_winsock (TRUE);
 10430 
 10431   /* Initial preparation for subprocess support: replace our standard
 10432      handles with non-inheritable versions. */
 10433   {
 10434     HANDLE parent;
 10435     HANDLE stdin_save =  INVALID_HANDLE_VALUE;
 10436     HANDLE stdout_save = INVALID_HANDLE_VALUE;
 10437     HANDLE stderr_save = INVALID_HANDLE_VALUE;
 10438 
 10439     parent = GetCurrentProcess ();
 10440 
 10441     /* ignore errors when duplicating and closing; typically the
 10442        handles will be invalid when running as a gui program. */
 10443     DuplicateHandle (parent,
 10444                      GetStdHandle (STD_INPUT_HANDLE),
 10445                      parent,
 10446                      &stdin_save,
 10447                      0,
 10448                      FALSE,
 10449                      DUPLICATE_SAME_ACCESS);
 10450 
 10451     DuplicateHandle (parent,
 10452                      GetStdHandle (STD_OUTPUT_HANDLE),
 10453                      parent,
 10454                      &stdout_save,
 10455                      0,
 10456                      FALSE,
 10457                      DUPLICATE_SAME_ACCESS);
 10458 
 10459     DuplicateHandle (parent,
 10460                      GetStdHandle (STD_ERROR_HANDLE),
 10461                      parent,
 10462                      &stderr_save,
 10463                      0,
 10464                      FALSE,
 10465                      DUPLICATE_SAME_ACCESS);
 10466 
 10467     fclose (stdin);
 10468     fclose (stdout);
 10469     fclose (stderr);
 10470 
 10471     if (stdin_save != INVALID_HANDLE_VALUE)
 10472       _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
 10473     else
 10474       _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
 10475     _fdopen (0, "r");
 10476 
 10477     if (stdout_save != INVALID_HANDLE_VALUE)
 10478       _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
 10479     else
 10480       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
 10481     _fdopen (1, "w");
 10482 
 10483     if (stderr_save != INVALID_HANDLE_VALUE)
 10484       _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
 10485     else
 10486       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
 10487     _fdopen (2, "w");
 10488   }
 10489 
 10490   /* unfortunately, atexit depends on implementation of malloc */
 10491   /* atexit (term_ntproc); */
 10492   if (!dumping)
 10493     {
 10494       /* Make sure we start with all signals unblocked.  */
 10495       sigprocmask (SIG_SETMASK, &initial_mask, NULL);
 10496       signal (SIGABRT, term_ntproc);
 10497     }
 10498   init_timers ();
 10499 
 10500   /* determine which drives are fixed, for GetCachedVolumeInformation */
 10501   {
 10502     /* GetDriveType must have trailing backslash. */
 10503     char drive[] = "A:\\";
 10504 
 10505     /* Loop over all possible drive letters */
 10506     while (*drive <= 'Z')
 10507     {
 10508       /* Record if this drive letter refers to a fixed drive. */
 10509       fixed_drives[DRIVE_INDEX (*drive)] =
 10510         (GetDriveType (drive) == DRIVE_FIXED);
 10511 
 10512       (*drive)++;
 10513     }
 10514 
 10515     /* Reset the volume info cache.  */
 10516     volume_cache = NULL;
 10517   }
 10518 }
 10519 
 10520 /* shutdown_handler ensures that buffers' autosave files are up to
 10521    date when the user logs off, or the system shuts down.  It also
 10522    shuts down Emacs when we get killed by another Emacs process, in
 10523    which case we get the CTRL_CLOSE_EVENT.  */
 10524 
 10525 extern DWORD dwMainThreadId;
 10526 
 10527 static BOOL WINAPI
 10528 shutdown_handler (DWORD type)
 10529 {
 10530   /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them.  */
 10531   if (type == CTRL_CLOSE_EVENT        /* User closes console window.  */
 10532       || type == CTRL_LOGOFF_EVENT    /* User logs off.  */
 10533       || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown.  */
 10534     {
 10535       if (GetCurrentThreadId () == dwMainThreadId)
 10536         {
 10537           /* If we are being shut down in noninteractive mode, we don't
 10538              care about the message stack, so clear it to avoid abort in
 10539              shut_down_emacs.  This happens when an noninteractive Emacs
 10540              is invoked as a subprocess of Emacs, and the parent wants to
 10541              kill us, e.g. because it's about to exit.  */
 10542           if (noninteractive)
 10543             clear_message_stack ();
 10544           /* Shut down cleanly, making sure autosave files are up to date.  */
 10545           shut_down_emacs (0, Qnil);
 10546         }
 10547       else
 10548         {
 10549           /* This handler is run in a thread different from the main
 10550              thread.  (This is the normal situation when we are killed
 10551              by Emacs, for example, which sends us the WM_CLOSE
 10552              message).  We cannot possibly call functions like
 10553              shut_down_emacs or clear_message_stack in that case,
 10554              since the main (a.k.a. "Lisp") thread could be in the
 10555              middle of some Lisp program.  So instead we arrange for
 10556              maybe_quit to kill Emacs.  */
 10557           Vquit_flag = Qkill_emacs;
 10558           Vinhibit_quit = Qnil;
 10559         }
 10560     }
 10561 
 10562   /* Allow other handlers to handle this signal.  */
 10563   return FALSE;
 10564 }
 10565 
 10566 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die.  On
 10567    NT, return a handle to GDI32.DLL.  */
 10568 HANDLE
 10569 maybe_load_unicows_dll (void)
 10570 {
 10571   if (os_subtype == OS_SUBTYPE_9X)
 10572     {
 10573       HANDLE ret = LoadLibrary ("Unicows.dll");
 10574       if (ret)
 10575         {
 10576           /* These two functions are present on Windows 9X as stubs
 10577              that always fail.  We need the real implementations from
 10578              UNICOWS.DLL, so we must call these functions through
 10579              pointers, and assign the correct addresses to these
 10580              pointers at program startup (see emacs.c, which calls
 10581              this function early on).  */
 10582           pMultiByteToWideChar = (MultiByteToWideChar_Proc)
 10583             get_proc_addr (ret, "MultiByteToWideChar");
 10584           pWideCharToMultiByte = (WideCharToMultiByte_Proc)
 10585             get_proc_addr (ret, "WideCharToMultiByte");
 10586           multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
 10587           return ret;
 10588         }
 10589       else
 10590         {
 10591           int button;
 10592 
 10593           button = MessageBox (NULL,
 10594                                "Emacs cannot load the UNICOWS.DLL library.\n"
 10595                                "This library is essential for using Emacs\n"
 10596                                "on this system.  You need to install it.\n\n"
 10597                                "Emacs will exit when you click OK.",
 10598                                "Emacs cannot load UNICOWS.DLL",
 10599                                MB_ICONERROR | MB_TASKMODAL
 10600                                | MB_SETFOREGROUND | MB_OK);
 10601           switch (button)
 10602             {
 10603             case IDOK:
 10604             default:
 10605               exit (1);
 10606             }
 10607         }
 10608     }
 10609   else
 10610     {
 10611       /* On NT family of Windows, these two functions are always
 10612          linked in, so we just assign their addresses to the 2
 10613          pointers; no need for the LoadLibrary dance.  */
 10614       pMultiByteToWideChar = MultiByteToWideChar;
 10615       pWideCharToMultiByte = WideCharToMultiByte;
 10616       /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported.  */
 10617       if (w32_major_version < 5)
 10618         multiByteToWideCharFlags = 0;
 10619       else
 10620         multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
 10621       return LoadLibrary ("Gdi32.dll");
 10622     }
 10623 }
 10624 
 10625 /* Relocate a directory specified by epaths.h, using the location of
 10626    our binary as an anchor.  Note: this runs early during startup, so
 10627    we cannot rely on the usual file-related facilities, and in
 10628    particular the argument is assumed to be a unibyte string in system
 10629    codepage encoding.  */
 10630 const char *
 10631 w32_relocate (const char *epath_dir)
 10632 {
 10633   if (strncmp (epath_dir, "%emacs_dir%/", 12) == 0)
 10634     {
 10635       static char relocated_dir[MAX_PATH];
 10636 
 10637       /* Replace "%emacs_dir%" with the parent of the directory where
 10638          our binary lives.  Note that init_environment was not yet
 10639          called, so we cannot rely on emacs_dir being set in the
 10640          environment.  */
 10641       if (GetModuleFileNameA (NULL, relocated_dir, MAX_PATH))
 10642         {
 10643           char *p = _mbsrchr (relocated_dir, '\\');
 10644 
 10645           if (p)
 10646             {
 10647               *p = '\0';
 10648               if ((p = _mbsrchr (relocated_dir, '\\')) != NULL)
 10649                 {
 10650                   strcpy (p, epath_dir + 11);
 10651                   epath_dir = relocated_dir;
 10652                 }
 10653             }
 10654         }
 10655     }
 10656   return epath_dir;
 10657 }
 10658 
 10659 /* Return the full absolute name of the running executable.  If the
 10660    executable is a symlink, resolve it.
 10661 
 10662    Note: this function is called early during startup, when Unicode
 10663    file names are not yet supported.  Thus the result must be an
 10664    ANSI-encoded string.  */
 10665 char *
 10666 w32_my_exename (void)
 10667 {
 10668   static char exename[MAX_PATH];
 10669   if (!GetModuleFileNameA (NULL, exename, MAX_PATH))
 10670     return NULL;
 10671   /* The caller expects us to resolve all possible symlinks in the
 10672      last component of exename, i.e. if the executable itself is a
 10673      symlink to a file in another directory.  */
 10674   if (get_volume_info (exename, NULL)
 10675       && (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
 10676     {
 10677       /* chase_symlinks wants its argument in UTF-8.  */
 10678       char exename_utf8[MAX_UTF8_PATH];
 10679       filename_from_ansi (exename, exename_utf8);
 10680 
 10681       /* If EXENAME is a symlink, replace it with its target.  */
 10682       char *tgt = chase_symlinks (exename_utf8);
 10683       if (tgt != exename_utf8)
 10684         filename_to_ansi (tgt, exename);
 10685     }
 10686 
 10687   return exename;
 10688 }
 10689 
 10690 /* Emulate Posix 'realpath'.  This is needed in
 10691    comp-el-to-eln-rel-filename.  */
 10692 char *
 10693 realpath (const char *file_name, char *resolved_name)
 10694 {
 10695   char *tgt = chase_symlinks (file_name);
 10696   char target[MAX_UTF8_PATH];
 10697 
 10698   if (tgt == file_name)
 10699     {
 10700       /* If FILE_NAME is not a symlink, chase_symlinks returns its
 10701          argument, possibly not in canonical absolute form.  Make sure
 10702          we return a canonical file name.  */
 10703       if (w32_unicode_filenames)
 10704         {
 10705           wchar_t file_w[MAX_PATH], tgt_w[MAX_PATH];
 10706 
 10707           filename_to_utf16 (file_name, file_w);
 10708           if (GetFullPathNameW (file_w, MAX_PATH, tgt_w, NULL) == 0)
 10709             return NULL;
 10710           filename_from_utf16 (tgt_w, target);
 10711         }
 10712       else
 10713         {
 10714           char file_a[MAX_PATH], tgt_a[MAX_PATH];
 10715 
 10716           filename_to_ansi (file_name, file_a);
 10717           if (GetFullPathNameA (file_a, MAX_PATH, tgt_a, NULL) == 0)
 10718             return NULL;
 10719           filename_from_ansi (tgt_a, target);
 10720         }
 10721       tgt = target;
 10722     }
 10723 
 10724   if (resolved_name)
 10725     return strcpy (resolved_name, tgt);
 10726   return xstrdup (tgt);
 10727 }
 10728 
 10729 static void
 10730 get_console_font_size (HANDLE hscreen, int *font_width, int *font_height)
 10731 {
 10732   static GetCurrentConsoleFont_Proc s_pfn_Get_Current_Console_Font = NULL;
 10733   static GetConsoleFontSize_Proc s_pfn_Get_Console_Font_Size = NULL;
 10734 
 10735   /* Default guessed values, for when we cannot obtain the actual ones.  */
 10736   *font_width = 8;
 10737   *font_height = 12;
 10738 
 10739   if (!is_windows_9x ())
 10740     {
 10741       if (g_b_init_get_console_font_size == 0)
 10742         {
 10743           HMODULE hm_kernel32 = LoadLibrary ("Kernel32.dll");
 10744           if (hm_kernel32)
 10745             {
 10746               s_pfn_Get_Current_Console_Font = (GetCurrentConsoleFont_Proc)
 10747                 get_proc_addr (hm_kernel32, "GetCurrentConsoleFont");
 10748               s_pfn_Get_Console_Font_Size = (GetConsoleFontSize_Proc)
 10749                 get_proc_addr (hm_kernel32, "GetConsoleFontSize");
 10750             }
 10751           g_b_init_get_console_font_size = 1;
 10752         }
 10753     }
 10754   if (s_pfn_Get_Current_Console_Font && s_pfn_Get_Console_Font_Size)
 10755     {
 10756       CONSOLE_FONT_INFO font_info;
 10757 
 10758       if (s_pfn_Get_Current_Console_Font (hscreen, FALSE, &font_info))
 10759         {
 10760           COORD font_size = s_pfn_Get_Console_Font_Size (hscreen,
 10761                                                          font_info.nFont);
 10762           if (font_size.X > 0)
 10763             *font_width = font_size.X;
 10764           if (font_size.Y > 0)
 10765             *font_height = font_size.Y;
 10766         }
 10767     }
 10768 }
 10769 
 10770 /* A replacement for Posix execvp, used to restart Emacs.  This is
 10771    needed because the low-level Windows API to start processes accepts
 10772    the command-line arguments as a single string, so we cannot safely
 10773    use the MSVCRT execvp emulation, because elements of argv[] that
 10774    have embedded blanks and tabs will not be passed correctly to the
 10775    restarted Emacs.  */
 10776 int
 10777 w32_reexec_emacs (char *cmd_line, const char *wdir)
 10778 {
 10779   STARTUPINFO si;
 10780   BOOL status;
 10781   PROCESS_INFORMATION proc_info;
 10782   DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS;
 10783 
 10784   GetStartupInfo (&si);         /* Use the same startup info as the caller.  */
 10785   if (inhibit_window_system)
 10786     {
 10787       HANDLE screen_handle;
 10788       CONSOLE_SCREEN_BUFFER_INFO screen_info;
 10789 
 10790       screen_handle = GetStdHandle (STD_OUTPUT_HANDLE);
 10791       if (screen_handle != INVALID_HANDLE_VALUE
 10792           && GetConsoleScreenBufferInfo (screen_handle, &screen_info))
 10793         {
 10794           int font_width, font_height;
 10795 
 10796           /* Make the restarted Emacs's console window the same
 10797              dimensions as ours.  */
 10798           si.dwXCountChars = screen_info.dwSize.X;
 10799           si.dwYCountChars = screen_info.dwSize.Y;
 10800           get_console_font_size (screen_handle, &font_width, &font_height);
 10801           si.dwXSize =
 10802             (screen_info.srWindow.Right - screen_info.srWindow.Left + 1)
 10803             * font_width;
 10804           si.dwYSize =
 10805             (screen_info.srWindow.Bottom - screen_info.srWindow.Top + 1)
 10806             * font_height;
 10807           si.dwFlags |= STARTF_USESIZE | STARTF_USECOUNTCHARS;
 10808         }
 10809       /* This is a kludge: it causes the restarted "emacs -nw" to have
 10810          a new console window created for it, and that new window
 10811          might have different (default) properties, not the ones of
 10812          the parent process's console window.  But without this,
 10813          restarting Emacs in the -nw mode simply doesn't work,
 10814          probably because the parent's console is still in use.
 10815          FIXME!  */
 10816       dwCreationFlags = CREATE_NEW_CONSOLE;
 10817     }
 10818 
 10819   /* Make sure we are in the original directory, in case the command
 10820      line specifies the program as a relative file name.  */
 10821   chdir (wdir);
 10822 
 10823   status = CreateProcess (NULL,         /* no program, take from command line */
 10824                           cmd_line,     /* command line */
 10825                           NULL,
 10826                           NULL,         /* thread attributes */
 10827                           FALSE,        /* unherit handles? */
 10828                           dwCreationFlags,
 10829                           NULL,         /* environment */
 10830                           wdir,         /* initial directory */
 10831                           &si,          /* startup info */
 10832                           &proc_info);
 10833   if (status)
 10834     {
 10835       CloseHandle (proc_info.hThread);
 10836       CloseHandle (proc_info.hProcess);
 10837       exit (0);
 10838     }
 10839   errno = ENOEXEC;
 10840   return -1;
 10841 }
 10842 
 10843 /*
 10844         globals_of_w32 is used to initialize those global variables that
 10845         must always be initialized on startup even when the global variable
 10846         initialized is non zero (see the function main in emacs.c).
 10847 */
 10848 void
 10849 globals_of_w32 (void)
 10850 {
 10851   HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
 10852 
 10853   get_process_times_fn = (GetProcessTimes_Proc)
 10854     get_proc_addr (kernel32, "GetProcessTimes");
 10855 
 10856   DEFSYM (QCloaded_from, ":loaded-from");
 10857 
 10858   g_b_init_is_windows_9x = 0;
 10859   g_b_init_open_process_token = 0;
 10860   g_b_init_get_token_information = 0;
 10861   g_b_init_lookup_account_sid = 0;
 10862   g_b_init_get_sid_sub_authority = 0;
 10863   g_b_init_get_sid_sub_authority_count = 0;
 10864   g_b_init_get_security_info = 0;
 10865   g_b_init_get_file_security_w = 0;
 10866   g_b_init_get_file_security_a = 0;
 10867   g_b_init_get_security_descriptor_owner = 0;
 10868   g_b_init_get_security_descriptor_group = 0;
 10869   g_b_init_is_valid_sid = 0;
 10870   g_b_init_create_toolhelp32_snapshot = 0;
 10871   g_b_init_process32_first = 0;
 10872   g_b_init_process32_next = 0;
 10873   g_b_init_open_thread_token = 0;
 10874   g_b_init_impersonate_self = 0;
 10875   g_b_init_revert_to_self = 0;
 10876   g_b_init_get_process_memory_info = 0;
 10877   g_b_init_get_process_working_set_size = 0;
 10878   g_b_init_global_memory_status = 0;
 10879   g_b_init_global_memory_status_ex = 0;
 10880   g_b_init_equal_sid = 0;
 10881   g_b_init_copy_sid = 0;
 10882   g_b_init_get_length_sid = 0;
 10883   g_b_init_get_native_system_info = 0;
 10884   g_b_init_get_system_times = 0;
 10885   g_b_init_create_symbolic_link_w = 0;
 10886   g_b_init_create_symbolic_link_a = 0;
 10887   g_b_init_get_security_descriptor_dacl = 0;
 10888   g_b_init_convert_sd_to_sddl = 0;
 10889   g_b_init_convert_sddl_to_sd = 0;
 10890   g_b_init_is_valid_security_descriptor = 0;
 10891   g_b_init_set_file_security_w = 0;
 10892   g_b_init_set_file_security_a = 0;
 10893   g_b_init_set_named_security_info_w = 0;
 10894   g_b_init_set_named_security_info_a = 0;
 10895   g_b_init_get_adapters_info = 0;
 10896   g_b_init_get_adapters_addresses = 0;
 10897   g_b_init_reg_open_key_ex_w = 0;
 10898   g_b_init_reg_query_value_ex_w = 0;
 10899   g_b_init_expand_environment_strings_w = 0;
 10900   g_b_init_compare_string_w = 0;
 10901   g_b_init_debug_break_process = 0;
 10902   g_b_init_get_user_default_ui_language = 0;
 10903   g_b_init_get_console_font_size = 0;
 10904   num_of_processors = 0;
 10905   /* The following sets a handler for shutdown notifications for
 10906      console apps. This actually applies to Emacs in both console and
 10907      GUI modes, since we had to fool windows into thinking emacs is a
 10908      console application to get console mode to work.  */
 10909   SetConsoleCtrlHandler (shutdown_handler, TRUE);
 10910 
 10911   /* "None" is the default group name on standalone workstations.  */
 10912   strcpy (dflt_group_name, "None");
 10913 
 10914   /* Reset, in case it has some value inherited from dump time.  */
 10915   w32_stat_get_owner_group = 0;
 10916 
 10917   /* If w32_unicode_filenames is non-zero, we will be using Unicode
 10918      (a.k.a. "wide") APIs to invoke functions that accept file
 10919      names.  */
 10920   if (is_windows_9x ())
 10921     w32_unicode_filenames = 0;
 10922   else
 10923     w32_unicode_filenames = 1;
 10924 
 10925 #ifdef HAVE_MODULES
 10926   dynlib_reset_last_error ();
 10927 #endif
 10928 
 10929   w32_crypto_hprov = (HCRYPTPROV)0;
 10930 
 10931   /* We need to forget about libraries that were loaded during the
 10932      dumping process (e.g. libgccjit) */
 10933   Vlibrary_cache = Qnil;
 10934 }
 10935 
 10936 /* For make-serial-process  */
 10937 int
 10938 serial_open (Lisp_Object port_obj)
 10939 {
 10940   char *port = SSDATA (port_obj);
 10941   HANDLE hnd;
 10942   child_process *cp;
 10943   int fd = -1;
 10944 
 10945   hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
 10946                     OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
 10947   if (hnd == INVALID_HANDLE_VALUE)
 10948     error ("Could not open %s", port);
 10949   fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
 10950   if (fd == -1)
 10951     error ("Could not open %s", port);
 10952 
 10953   cp = new_child ();
 10954   if (!cp)
 10955     error ("Could not create child process");
 10956   cp->fd = fd;
 10957   cp->status = STATUS_READ_ACKNOWLEDGED;
 10958   fd_info[ fd ].hnd = hnd;
 10959   fd_info[ fd ].flags |=
 10960     FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
 10961   if (fd_info[ fd ].cp != NULL)
 10962     {
 10963       error ("fd_info[fd = %d] is already in use", fd);
 10964     }
 10965   fd_info[ fd ].cp = cp;
 10966   cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
 10967   if (cp->ovl_read.hEvent == NULL)
 10968       error ("Could not create read event");
 10969   cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
 10970   if (cp->ovl_write.hEvent == NULL)
 10971       error ("Could not create write event");
 10972 
 10973   return fd;
 10974 }
 10975 
 10976 /* For serial-process-configure  */
 10977 void
 10978 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
 10979 {
 10980   Lisp_Object childp2 = Qnil;
 10981   Lisp_Object tem = Qnil;
 10982   HANDLE hnd;
 10983   DCB dcb;
 10984   COMMTIMEOUTS ct;
 10985   char summary[4] = "???"; /* This usually becomes "8N1".  */
 10986 
 10987   if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
 10988     error ("Not a serial process");
 10989   hnd = fd_info[ p->outfd ].hnd;
 10990 
 10991   childp2 = Fcopy_sequence (p->childp);
 10992 
 10993   /* Initialize timeouts for blocking read and blocking write.  */
 10994   if (!GetCommTimeouts (hnd, &ct))
 10995     error ("GetCommTimeouts() failed");
 10996   ct.ReadIntervalTimeout         = 0;
 10997   ct.ReadTotalTimeoutMultiplier  = 0;
 10998   ct.ReadTotalTimeoutConstant    = 0;
 10999   ct.WriteTotalTimeoutMultiplier = 0;
 11000   ct.WriteTotalTimeoutConstant   = 0;
 11001   if (!SetCommTimeouts (hnd, &ct))
 11002     error ("SetCommTimeouts() failed");
 11003   /* Read port attributes and prepare default configuration.  */
 11004   memset (&dcb, 0, sizeof (dcb));
 11005   dcb.DCBlength = sizeof (DCB);
 11006   if (!GetCommState (hnd, &dcb))
 11007     error ("GetCommState() failed");
 11008   dcb.fBinary       = TRUE;
 11009   dcb.fNull         = FALSE;
 11010   dcb.fAbortOnError = FALSE;
 11011   /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
 11012   dcb.ErrorChar     = 0;
 11013   dcb.EofChar       = 0;
 11014   dcb.EvtChar       = 0;
 11015 
 11016   /* Configure speed.  */
 11017   if (!NILP (plist_member (contact, QCspeed)))
 11018     tem = plist_get (contact, QCspeed);
 11019   else
 11020     tem = plist_get (p->childp, QCspeed);
 11021   CHECK_FIXNUM (tem);
 11022   dcb.BaudRate = XFIXNUM (tem);
 11023   childp2 = plist_put (childp2, QCspeed, tem);
 11024 
 11025   /* Configure bytesize.  */
 11026   if (!NILP (plist_member (contact, QCbytesize)))
 11027     tem = plist_get (contact, QCbytesize);
 11028   else
 11029     tem = plist_get (p->childp, QCbytesize);
 11030   if (NILP (tem))
 11031     tem = make_fixnum (8);
 11032   CHECK_FIXNUM (tem);
 11033   if (XFIXNUM (tem) != 7 && XFIXNUM (tem) != 8)
 11034     error (":bytesize must be nil (8), 7, or 8");
 11035   dcb.ByteSize = XFIXNUM (tem);
 11036   summary[0] = XFIXNUM (tem) + '0';
 11037   childp2 = plist_put (childp2, QCbytesize, tem);
 11038 
 11039   /* Configure parity.  */
 11040   if (!NILP (plist_member (contact, QCparity)))
 11041     tem = plist_get (contact, QCparity);
 11042   else
 11043     tem = plist_get (p->childp, QCparity);
 11044   if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
 11045     error (":parity must be nil (no parity), `even', or `odd'");
 11046   dcb.fParity = FALSE;
 11047   dcb.Parity = NOPARITY;
 11048   dcb.fErrorChar = FALSE;
 11049   if (NILP (tem))
 11050     {
 11051       summary[1] = 'N';
 11052     }
 11053   else if (EQ (tem, Qeven))
 11054     {
 11055       summary[1] = 'E';
 11056       dcb.fParity = TRUE;
 11057       dcb.Parity = EVENPARITY;
 11058       dcb.fErrorChar = TRUE;
 11059     }
 11060   else if (EQ (tem, Qodd))
 11061     {
 11062       summary[1] = 'O';
 11063       dcb.fParity = TRUE;
 11064       dcb.Parity = ODDPARITY;
 11065       dcb.fErrorChar = TRUE;
 11066     }
 11067   childp2 = plist_put (childp2, QCparity, tem);
 11068 
 11069   /* Configure stopbits.  */
 11070   if (!NILP (plist_member (contact, QCstopbits)))
 11071     tem = plist_get (contact, QCstopbits);
 11072   else
 11073     tem = plist_get (p->childp, QCstopbits);
 11074   if (NILP (tem))
 11075     tem = make_fixnum (1);
 11076   CHECK_FIXNUM (tem);
 11077   if (XFIXNUM (tem) != 1 && XFIXNUM (tem) != 2)
 11078     error (":stopbits must be nil (1 stopbit), 1, or 2");
 11079   summary[2] = XFIXNUM (tem) + '0';
 11080   if (XFIXNUM (tem) == 1)
 11081     dcb.StopBits = ONESTOPBIT;
 11082   else if (XFIXNUM (tem) == 2)
 11083     dcb.StopBits = TWOSTOPBITS;
 11084   childp2 = plist_put (childp2, QCstopbits, tem);
 11085 
 11086   /* Configure flowcontrol.  */
 11087   if (!NILP (plist_member (contact, QCflowcontrol)))
 11088     tem = plist_get (contact, QCflowcontrol);
 11089   else
 11090     tem = plist_get (p->childp, QCflowcontrol);
 11091   if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
 11092     error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
 11093   dcb.fOutxCtsFlow      = FALSE;
 11094   dcb.fOutxDsrFlow      = FALSE;
 11095   dcb.fDtrControl       = DTR_CONTROL_DISABLE;
 11096   dcb.fDsrSensitivity   = FALSE;
 11097   dcb.fTXContinueOnXoff = FALSE;
 11098   dcb.fOutX             = FALSE;
 11099   dcb.fInX              = FALSE;
 11100   dcb.fRtsControl       = RTS_CONTROL_DISABLE;
 11101   dcb.XonChar           = 17; /* Control-Q  */
 11102   dcb.XoffChar          = 19; /* Control-S  */
 11103   if (NILP (tem))
 11104     {
 11105       /* Already configured.  */
 11106     }
 11107   else if (EQ (tem, Qhw))
 11108     {
 11109       dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
 11110       dcb.fOutxCtsFlow = TRUE;
 11111     }
 11112   else if (EQ (tem, Qsw))
 11113     {
 11114       dcb.fOutX = TRUE;
 11115       dcb.fInX = TRUE;
 11116     }
 11117   childp2 = plist_put (childp2, QCflowcontrol, tem);
 11118 
 11119   /* Activate configuration.  */
 11120   if (!SetCommState (hnd, &dcb))
 11121     error ("SetCommState() failed");
 11122 
 11123   childp2 = plist_put (childp2, QCsummary, build_string (summary));
 11124   pset_childp (p, childp2);
 11125 }
 11126 
 11127 /* For make-pipe-process */
 11128 void
 11129 register_aux_fd (int infd)
 11130 {
 11131   child_process *cp;
 11132 
 11133   cp = new_child ();
 11134   if (!cp)
 11135     error ("Could not create child process");
 11136   cp->fd = infd;
 11137   cp->status = STATUS_READ_ACKNOWLEDGED;
 11138 
 11139   if (fd_info[ infd ].cp != NULL)
 11140     {
 11141       error ("fd_info[fd = %d] is already in use", infd);
 11142     }
 11143   fd_info[ infd ].cp = cp;
 11144   fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
 11145   fd_info[ infd ].flags |= FILE_DONT_CLOSE;
 11146 }
 11147 
 11148 #ifdef HAVE_GNUTLS
 11149 
 11150 ssize_t
 11151 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 11152 {
 11153   int n, err;
 11154   struct Lisp_Process *process = (struct Lisp_Process *)p;
 11155   int fd = process->infd;
 11156 
 11157   n = sys_read (fd, (char*)buf, sz);
 11158 
 11159   if (n >= 0)
 11160     return n;
 11161 
 11162   err = errno;
 11163 
 11164   /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
 11165   if (err == EWOULDBLOCK)
 11166     err = EAGAIN;
 11167 
 11168   emacs_gnutls_transport_set_errno (process->gnutls_state, err);
 11169 
 11170   return -1;
 11171 }
 11172 
 11173 ssize_t
 11174 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
 11175 {
 11176   struct Lisp_Process *process = (struct Lisp_Process *)p;
 11177   int fd = process->outfd;
 11178   ssize_t n = sys_write (fd, buf, sz);
 11179 
 11180   /* 0 or more bytes written means everything went fine.  */
 11181   if (n >= 0)
 11182     return n;
 11183 
 11184   /* Negative bytes written means we got an error in errno.
 11185      Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.  */
 11186   emacs_gnutls_transport_set_errno (process->gnutls_state,
 11187                                     errno == EWOULDBLOCK ? EAGAIN : errno);
 11188 
 11189   return -1;
 11190 }
 11191 #endif /* HAVE_GNUTLS */
 11192 
 11193 /* end of w32.c */

/* [<][>][^][v][top][bottom][index][help] */