Spelling fix: prefer "cooperate" to "co-operate"
[emacs.git] / src / w32.c
blob9b1d94de7862f359bd50ab1ab2b77a02f0027dfa
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2015 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #include <mingw_time.h>
25 #include <stddef.h> /* for offsetof */
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <float.h> /* for DBL_EPSILON */
29 #include <io.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <sys/file.h>
35 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/time.h>
37 #include <sys/utime.h>
38 #include <math.h>
40 /* must include CRT headers *before* config.h */
42 #include <config.h>
43 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef open
54 #undef rename
55 #undef rmdir
56 #undef unlink
58 #undef close
59 #undef dup
60 #undef dup2
61 #undef pipe
62 #undef read
63 #undef write
65 #undef strerror
67 #undef localtime
69 #include "lisp.h"
70 #include "epaths.h" /* for PATH_EXEC */
72 #include <pwd.h>
73 #include <grp.h>
75 /* MinGW64 defines these in its _mingw.h. */
76 #ifndef _ANONYMOUS_UNION
77 # define _ANONYMOUS_UNION
78 #endif
79 #ifndef _ANONYMOUS_STRUCT
80 # define _ANONYMOUS_STRUCT
81 #endif
82 #include <windows.h>
83 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
84 use a different name to avoid compilation problems. */
85 typedef struct _MEMORY_STATUS_EX {
86 DWORD dwLength;
87 DWORD dwMemoryLoad;
88 DWORDLONG ullTotalPhys;
89 DWORDLONG ullAvailPhys;
90 DWORDLONG ullTotalPageFile;
91 DWORDLONG ullAvailPageFile;
92 DWORDLONG ullTotalVirtual;
93 DWORDLONG ullAvailVirtual;
94 DWORDLONG ullAvailExtendedVirtual;
95 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
97 /* These are here so that GDB would know about these data types. This
98 allows to attach GDB to Emacs when a fatal exception is triggered
99 and Windows pops up the "application needs to be closed" dialog.
100 At that point, _gnu_exception_handler, the top-level exception
101 handler installed by the MinGW startup code, is somewhere on the
102 call-stack of the main thread, so going to that call frame and
103 looking at the argument to _gnu_exception_handler, which is a
104 PEXCEPTION_POINTERS pointer, can reveal the exception code
105 (excptr->ExceptionRecord->ExceptionCode) and the address where the
106 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
107 well as some additional information specific to the exception. */
108 PEXCEPTION_POINTERS excptr;
109 PEXCEPTION_RECORD excprec;
110 PCONTEXT ctxrec;
112 #include <lmcons.h>
113 #include <shlobj.h>
115 #include <tlhelp32.h>
116 #include <psapi.h>
117 #ifndef _MSC_VER
118 #include <w32api.h>
119 #endif
120 #if _WIN32_WINNT < 0x0500
121 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
122 /* This either is not in psapi.h or guarded by higher value of
123 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
124 defines it in psapi.h */
125 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
126 DWORD cb;
127 DWORD PageFaultCount;
128 SIZE_T PeakWorkingSetSize;
129 SIZE_T WorkingSetSize;
130 SIZE_T QuotaPeakPagedPoolUsage;
131 SIZE_T QuotaPagedPoolUsage;
132 SIZE_T QuotaPeakNonPagedPoolUsage;
133 SIZE_T QuotaNonPagedPoolUsage;
134 SIZE_T PagefileUsage;
135 SIZE_T PeakPagefileUsage;
136 SIZE_T PrivateUsage;
137 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
138 #endif
139 #endif
141 #include <winioctl.h>
142 #include <aclapi.h>
143 #include <sddl.h>
145 #include <sys/acl.h>
146 #include <acl.h>
148 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
149 define them by hand if not already defined. */
150 #ifndef SDDL_REVISION_1
151 #define SDDL_REVISION_1 1
152 #endif /* SDDL_REVISION_1 */
154 #if defined(_MSC_VER) || defined(MINGW_W64)
155 /* MSVC and MinGW64 don't provide the definition of
156 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
157 which cannot be included because it triggers conflicts with other
158 Windows API headers. So we define it here by hand. */
160 typedef struct _REPARSE_DATA_BUFFER {
161 ULONG ReparseTag;
162 USHORT ReparseDataLength;
163 USHORT Reserved;
164 union {
165 struct {
166 USHORT SubstituteNameOffset;
167 USHORT SubstituteNameLength;
168 USHORT PrintNameOffset;
169 USHORT PrintNameLength;
170 ULONG Flags;
171 WCHAR PathBuffer[1];
172 } SymbolicLinkReparseBuffer;
173 struct {
174 USHORT SubstituteNameOffset;
175 USHORT SubstituteNameLength;
176 USHORT PrintNameOffset;
177 USHORT PrintNameLength;
178 WCHAR PathBuffer[1];
179 } MountPointReparseBuffer;
180 struct {
181 UCHAR DataBuffer[1];
182 } GenericReparseBuffer;
183 } DUMMYUNIONNAME;
184 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
186 #ifndef FILE_DEVICE_FILE_SYSTEM
187 #define FILE_DEVICE_FILE_SYSTEM 9
188 #endif
189 #ifndef METHOD_BUFFERED
190 #define METHOD_BUFFERED 0
191 #endif
192 #ifndef FILE_ANY_ACCESS
193 #define FILE_ANY_ACCESS 0x00000000
194 #endif
195 #ifndef CTL_CODE
196 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
197 #endif
198 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
199 #ifndef FSCTL_GET_REPARSE_POINT
200 #define FSCTL_GET_REPARSE_POINT \
201 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
202 #endif
203 #endif
205 /* TCP connection support. */
206 #include <sys/socket.h>
207 #undef socket
208 #undef bind
209 #undef connect
210 #undef htons
211 #undef ntohs
212 #undef inet_addr
213 #undef gethostname
214 #undef gethostbyname
215 #undef getservbyname
216 #undef getpeername
217 #undef shutdown
218 #undef setsockopt
219 #undef listen
220 #undef getsockname
221 #undef accept
222 #undef recvfrom
223 #undef sendto
225 #include <iphlpapi.h> /* should be after winsock2.h */
227 #include <c-strcase.h>
229 #include "w32.h"
230 #include <dirent.h>
231 #include "w32common.h"
232 #include "w32select.h"
233 #include "systime.h" /* for current_timespec, struct timespec */
234 #include "dispextern.h" /* for xstrcasecmp */
235 #include "coding.h" /* for Vlocale_coding_system */
237 #include "careadlinkat.h"
238 #include "allocator.h"
240 /* For Lisp_Process, serial_configure and serial_open. */
241 #include "process.h"
242 #include "systty.h"
244 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
245 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
247 void globals_of_w32 (void);
248 static DWORD get_rid (PSID);
249 static int is_symlink (const char *);
250 static char * chase_symlinks (const char *);
251 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
252 static int restore_privilege (TOKEN_PRIVILEGES *);
253 static BOOL WINAPI revert_to_self (void);
255 static int sys_access (const char *, int);
256 extern void *e_malloc (size_t);
257 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
258 struct timespec *, void *);
259 extern int sys_dup (int);
264 /* Initialization states.
266 WARNING: If you add any more such variables for additional APIs,
267 you MUST add initialization for them to globals_of_w32
268 below. This is because these variables might get set
269 to non-NULL values during dumping, but the dumped Emacs
270 cannot reuse those values, because it could be run on a
271 different version of the OS, where API addresses are
272 different. */
273 static BOOL g_b_init_is_windows_9x;
274 static BOOL g_b_init_open_process_token;
275 static BOOL g_b_init_get_token_information;
276 static BOOL g_b_init_lookup_account_sid;
277 static BOOL g_b_init_get_sid_sub_authority;
278 static BOOL g_b_init_get_sid_sub_authority_count;
279 static BOOL g_b_init_get_security_info;
280 static BOOL g_b_init_get_file_security_w;
281 static BOOL g_b_init_get_file_security_a;
282 static BOOL g_b_init_get_security_descriptor_owner;
283 static BOOL g_b_init_get_security_descriptor_group;
284 static BOOL g_b_init_is_valid_sid;
285 static BOOL g_b_init_create_toolhelp32_snapshot;
286 static BOOL g_b_init_process32_first;
287 static BOOL g_b_init_process32_next;
288 static BOOL g_b_init_open_thread_token;
289 static BOOL g_b_init_impersonate_self;
290 static BOOL g_b_init_revert_to_self;
291 static BOOL g_b_init_get_process_memory_info;
292 static BOOL g_b_init_get_process_working_set_size;
293 static BOOL g_b_init_global_memory_status;
294 static BOOL g_b_init_global_memory_status_ex;
295 static BOOL g_b_init_get_length_sid;
296 static BOOL g_b_init_equal_sid;
297 static BOOL g_b_init_copy_sid;
298 static BOOL g_b_init_get_native_system_info;
299 static BOOL g_b_init_get_system_times;
300 static BOOL g_b_init_create_symbolic_link_w;
301 static BOOL g_b_init_create_symbolic_link_a;
302 static BOOL g_b_init_get_security_descriptor_dacl;
303 static BOOL g_b_init_convert_sd_to_sddl;
304 static BOOL g_b_init_convert_sddl_to_sd;
305 static BOOL g_b_init_is_valid_security_descriptor;
306 static BOOL g_b_init_set_file_security_w;
307 static BOOL g_b_init_set_file_security_a;
308 static BOOL g_b_init_set_named_security_info_w;
309 static BOOL g_b_init_set_named_security_info_a;
310 static BOOL g_b_init_get_adapters_info;
312 BOOL g_b_init_compare_string_w;
315 BEGIN: Wrapper functions around OpenProcessToken
316 and other functions in advapi32.dll that are only
317 supported in Windows NT / 2k / XP
319 /* ** Function pointer typedefs ** */
320 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
321 HANDLE ProcessHandle,
322 DWORD DesiredAccess,
323 PHANDLE TokenHandle);
324 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
325 HANDLE TokenHandle,
326 TOKEN_INFORMATION_CLASS TokenInformationClass,
327 LPVOID TokenInformation,
328 DWORD TokenInformationLength,
329 PDWORD ReturnLength);
330 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
331 HANDLE process_handle,
332 LPFILETIME creation_time,
333 LPFILETIME exit_time,
334 LPFILETIME kernel_time,
335 LPFILETIME user_time);
337 GetProcessTimes_Proc get_process_times_fn = NULL;
339 #ifdef _UNICODE
340 const char * const LookupAccountSid_Name = "LookupAccountSidW";
341 #else
342 const char * const LookupAccountSid_Name = "LookupAccountSidA";
343 #endif
344 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
345 LPCTSTR lpSystemName,
346 PSID Sid,
347 LPTSTR Name,
348 LPDWORD cbName,
349 LPTSTR DomainName,
350 LPDWORD cbDomainName,
351 PSID_NAME_USE peUse);
352 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
353 PSID pSid,
354 DWORD n);
355 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
356 PSID pSid);
357 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
358 HANDLE handle,
359 SE_OBJECT_TYPE ObjectType,
360 SECURITY_INFORMATION SecurityInfo,
361 PSID *ppsidOwner,
362 PSID *ppsidGroup,
363 PACL *ppDacl,
364 PACL *ppSacl,
365 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
366 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
367 LPCWSTR lpFileName,
368 SECURITY_INFORMATION RequestedInformation,
369 PSECURITY_DESCRIPTOR pSecurityDescriptor,
370 DWORD nLength,
371 LPDWORD lpnLengthNeeded);
372 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
373 LPCSTR lpFileName,
374 SECURITY_INFORMATION RequestedInformation,
375 PSECURITY_DESCRIPTOR pSecurityDescriptor,
376 DWORD nLength,
377 LPDWORD lpnLengthNeeded);
378 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
379 LPCWSTR lpFileName,
380 SECURITY_INFORMATION SecurityInformation,
381 PSECURITY_DESCRIPTOR pSecurityDescriptor);
382 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
383 LPCSTR lpFileName,
384 SECURITY_INFORMATION SecurityInformation,
385 PSECURITY_DESCRIPTOR pSecurityDescriptor);
386 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
387 LPCWSTR lpObjectName,
388 SE_OBJECT_TYPE ObjectType,
389 SECURITY_INFORMATION SecurityInformation,
390 PSID psidOwner,
391 PSID psidGroup,
392 PACL pDacl,
393 PACL pSacl);
394 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
395 LPCSTR lpObjectName,
396 SE_OBJECT_TYPE ObjectType,
397 SECURITY_INFORMATION SecurityInformation,
398 PSID psidOwner,
399 PSID psidGroup,
400 PACL pDacl,
401 PACL pSacl);
402 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
403 PSECURITY_DESCRIPTOR pSecurityDescriptor,
404 PSID *pOwner,
405 LPBOOL lpbOwnerDefaulted);
406 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
407 PSECURITY_DESCRIPTOR pSecurityDescriptor,
408 PSID *pGroup,
409 LPBOOL lpbGroupDefaulted);
410 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
411 PSECURITY_DESCRIPTOR pSecurityDescriptor,
412 LPBOOL lpbDaclPresent,
413 PACL *pDacl,
414 LPBOOL lpbDaclDefaulted);
415 typedef BOOL (WINAPI * IsValidSid_Proc) (
416 PSID sid);
417 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
418 DWORD dwFlags,
419 DWORD th32ProcessID);
420 typedef BOOL (WINAPI * Process32First_Proc) (
421 HANDLE hSnapshot,
422 LPPROCESSENTRY32 lppe);
423 typedef BOOL (WINAPI * Process32Next_Proc) (
424 HANDLE hSnapshot,
425 LPPROCESSENTRY32 lppe);
426 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
427 HANDLE ThreadHandle,
428 DWORD DesiredAccess,
429 BOOL OpenAsSelf,
430 PHANDLE TokenHandle);
431 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
432 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
433 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
434 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
435 HANDLE Process,
436 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
437 DWORD cb);
438 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
439 HANDLE hProcess,
440 PSIZE_T lpMinimumWorkingSetSize,
441 PSIZE_T lpMaximumWorkingSetSize);
442 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
443 LPMEMORYSTATUS lpBuffer);
444 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
445 LPMEMORY_STATUS_EX lpBuffer);
446 typedef BOOL (WINAPI * CopySid_Proc) (
447 DWORD nDestinationSidLength,
448 PSID pDestinationSid,
449 PSID pSourceSid);
450 typedef BOOL (WINAPI * EqualSid_Proc) (
451 PSID pSid1,
452 PSID pSid2);
453 typedef DWORD (WINAPI * GetLengthSid_Proc) (
454 PSID pSid);
455 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
456 LPSYSTEM_INFO lpSystemInfo);
457 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
458 LPFILETIME lpIdleTime,
459 LPFILETIME lpKernelTime,
460 LPFILETIME lpUserTime);
461 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
462 LPCWSTR lpSymlinkFileName,
463 LPCWSTR lpTargetFileName,
464 DWORD dwFlags);
465 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
466 LPCSTR lpSymlinkFileName,
467 LPCSTR lpTargetFileName,
468 DWORD dwFlags);
469 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
470 LPCTSTR StringSecurityDescriptor,
471 DWORD StringSDRevision,
472 PSECURITY_DESCRIPTOR *SecurityDescriptor,
473 PULONG SecurityDescriptorSize);
474 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
475 PSECURITY_DESCRIPTOR SecurityDescriptor,
476 DWORD RequestedStringSDRevision,
477 SECURITY_INFORMATION SecurityInformation,
478 LPTSTR *StringSecurityDescriptor,
479 PULONG StringSecurityDescriptorLen);
480 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
481 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
482 PIP_ADAPTER_INFO pAdapterInfo,
483 PULONG pOutBufLen);
485 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
486 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
488 /* ** A utility function ** */
489 static BOOL
490 is_windows_9x (void)
492 static BOOL s_b_ret = 0;
493 OSVERSIONINFO os_ver;
494 if (g_b_init_is_windows_9x == 0)
496 g_b_init_is_windows_9x = 1;
497 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
498 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
499 if (GetVersionEx (&os_ver))
501 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
504 return s_b_ret;
507 static Lisp_Object ltime (ULONGLONG);
509 /* Get total user and system times for get-internal-run-time.
510 Returns a list of integers if the times are provided by the OS
511 (NT derivatives), otherwise it returns the result of current-time. */
512 Lisp_Object
513 w32_get_internal_run_time (void)
515 if (get_process_times_fn)
517 FILETIME create, exit, kernel, user;
518 HANDLE proc = GetCurrentProcess ();
519 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
521 LARGE_INTEGER user_int, kernel_int, total;
522 user_int.LowPart = user.dwLowDateTime;
523 user_int.HighPart = user.dwHighDateTime;
524 kernel_int.LowPart = kernel.dwLowDateTime;
525 kernel_int.HighPart = kernel.dwHighDateTime;
526 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
527 return ltime (total.QuadPart);
531 return Fcurrent_time ();
534 /* ** The wrapper functions ** */
536 static BOOL WINAPI
537 open_process_token (HANDLE ProcessHandle,
538 DWORD DesiredAccess,
539 PHANDLE TokenHandle)
541 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
542 HMODULE hm_advapi32 = NULL;
543 if (is_windows_9x () == TRUE)
545 return FALSE;
547 if (g_b_init_open_process_token == 0)
549 g_b_init_open_process_token = 1;
550 hm_advapi32 = LoadLibrary ("Advapi32.dll");
551 s_pfn_Open_Process_Token =
552 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
554 if (s_pfn_Open_Process_Token == NULL)
556 return FALSE;
558 return (
559 s_pfn_Open_Process_Token (
560 ProcessHandle,
561 DesiredAccess,
562 TokenHandle)
566 static BOOL WINAPI
567 get_token_information (HANDLE TokenHandle,
568 TOKEN_INFORMATION_CLASS TokenInformationClass,
569 LPVOID TokenInformation,
570 DWORD TokenInformationLength,
571 PDWORD ReturnLength)
573 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
574 HMODULE hm_advapi32 = NULL;
575 if (is_windows_9x () == TRUE)
577 return FALSE;
579 if (g_b_init_get_token_information == 0)
581 g_b_init_get_token_information = 1;
582 hm_advapi32 = LoadLibrary ("Advapi32.dll");
583 s_pfn_Get_Token_Information =
584 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
586 if (s_pfn_Get_Token_Information == NULL)
588 return FALSE;
590 return (
591 s_pfn_Get_Token_Information (
592 TokenHandle,
593 TokenInformationClass,
594 TokenInformation,
595 TokenInformationLength,
596 ReturnLength)
600 static BOOL WINAPI
601 lookup_account_sid (LPCTSTR lpSystemName,
602 PSID Sid,
603 LPTSTR Name,
604 LPDWORD cbName,
605 LPTSTR DomainName,
606 LPDWORD cbDomainName,
607 PSID_NAME_USE peUse)
609 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
610 HMODULE hm_advapi32 = NULL;
611 if (is_windows_9x () == TRUE)
613 return FALSE;
615 if (g_b_init_lookup_account_sid == 0)
617 g_b_init_lookup_account_sid = 1;
618 hm_advapi32 = LoadLibrary ("Advapi32.dll");
619 s_pfn_Lookup_Account_Sid =
620 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
622 if (s_pfn_Lookup_Account_Sid == NULL)
624 return FALSE;
626 return (
627 s_pfn_Lookup_Account_Sid (
628 lpSystemName,
629 Sid,
630 Name,
631 cbName,
632 DomainName,
633 cbDomainName,
634 peUse)
638 static PDWORD WINAPI
639 get_sid_sub_authority (PSID pSid, DWORD n)
641 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
642 static DWORD zero = 0U;
643 HMODULE hm_advapi32 = NULL;
644 if (is_windows_9x () == TRUE)
646 return &zero;
648 if (g_b_init_get_sid_sub_authority == 0)
650 g_b_init_get_sid_sub_authority = 1;
651 hm_advapi32 = LoadLibrary ("Advapi32.dll");
652 s_pfn_Get_Sid_Sub_Authority =
653 (GetSidSubAuthority_Proc) GetProcAddress (
654 hm_advapi32, "GetSidSubAuthority");
656 if (s_pfn_Get_Sid_Sub_Authority == NULL)
658 return &zero;
660 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
663 static PUCHAR WINAPI
664 get_sid_sub_authority_count (PSID pSid)
666 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
667 static UCHAR zero = 0U;
668 HMODULE hm_advapi32 = NULL;
669 if (is_windows_9x () == TRUE)
671 return &zero;
673 if (g_b_init_get_sid_sub_authority_count == 0)
675 g_b_init_get_sid_sub_authority_count = 1;
676 hm_advapi32 = LoadLibrary ("Advapi32.dll");
677 s_pfn_Get_Sid_Sub_Authority_Count =
678 (GetSidSubAuthorityCount_Proc) GetProcAddress (
679 hm_advapi32, "GetSidSubAuthorityCount");
681 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
683 return &zero;
685 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
688 static DWORD WINAPI
689 get_security_info (HANDLE handle,
690 SE_OBJECT_TYPE ObjectType,
691 SECURITY_INFORMATION SecurityInfo,
692 PSID *ppsidOwner,
693 PSID *ppsidGroup,
694 PACL *ppDacl,
695 PACL *ppSacl,
696 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
698 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
699 HMODULE hm_advapi32 = NULL;
700 if (is_windows_9x () == TRUE)
702 return FALSE;
704 if (g_b_init_get_security_info == 0)
706 g_b_init_get_security_info = 1;
707 hm_advapi32 = LoadLibrary ("Advapi32.dll");
708 s_pfn_Get_Security_Info =
709 (GetSecurityInfo_Proc) GetProcAddress (
710 hm_advapi32, "GetSecurityInfo");
712 if (s_pfn_Get_Security_Info == NULL)
714 return FALSE;
716 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
717 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
718 ppSecurityDescriptor));
721 static BOOL WINAPI
722 get_file_security (const char *lpFileName,
723 SECURITY_INFORMATION RequestedInformation,
724 PSECURITY_DESCRIPTOR pSecurityDescriptor,
725 DWORD nLength,
726 LPDWORD lpnLengthNeeded)
728 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
729 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
730 HMODULE hm_advapi32 = NULL;
731 if (is_windows_9x () == TRUE)
733 errno = ENOTSUP;
734 return FALSE;
736 if (w32_unicode_filenames)
738 wchar_t filename_w[MAX_PATH];
740 if (g_b_init_get_file_security_w == 0)
742 g_b_init_get_file_security_w = 1;
743 hm_advapi32 = LoadLibrary ("Advapi32.dll");
744 s_pfn_Get_File_SecurityW =
745 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
746 "GetFileSecurityW");
748 if (s_pfn_Get_File_SecurityW == NULL)
750 errno = ENOTSUP;
751 return FALSE;
753 filename_to_utf16 (lpFileName, filename_w);
754 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
755 pSecurityDescriptor, nLength,
756 lpnLengthNeeded));
758 else
760 char filename_a[MAX_PATH];
762 if (g_b_init_get_file_security_a == 0)
764 g_b_init_get_file_security_a = 1;
765 hm_advapi32 = LoadLibrary ("Advapi32.dll");
766 s_pfn_Get_File_SecurityA =
767 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
768 "GetFileSecurityA");
770 if (s_pfn_Get_File_SecurityA == NULL)
772 errno = ENOTSUP;
773 return FALSE;
775 filename_to_ansi (lpFileName, filename_a);
776 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
777 pSecurityDescriptor, nLength,
778 lpnLengthNeeded));
782 static BOOL WINAPI
783 set_file_security (const char *lpFileName,
784 SECURITY_INFORMATION SecurityInformation,
785 PSECURITY_DESCRIPTOR pSecurityDescriptor)
787 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
788 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
789 HMODULE hm_advapi32 = NULL;
790 if (is_windows_9x () == TRUE)
792 errno = ENOTSUP;
793 return FALSE;
795 if (w32_unicode_filenames)
797 wchar_t filename_w[MAX_PATH];
799 if (g_b_init_set_file_security_w == 0)
801 g_b_init_set_file_security_w = 1;
802 hm_advapi32 = LoadLibrary ("Advapi32.dll");
803 s_pfn_Set_File_SecurityW =
804 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
805 "SetFileSecurityW");
807 if (s_pfn_Set_File_SecurityW == NULL)
809 errno = ENOTSUP;
810 return FALSE;
812 filename_to_utf16 (lpFileName, filename_w);
813 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
814 pSecurityDescriptor));
816 else
818 char filename_a[MAX_PATH];
820 if (g_b_init_set_file_security_a == 0)
822 g_b_init_set_file_security_a = 1;
823 hm_advapi32 = LoadLibrary ("Advapi32.dll");
824 s_pfn_Set_File_SecurityA =
825 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
826 "SetFileSecurityA");
828 if (s_pfn_Set_File_SecurityA == NULL)
830 errno = ENOTSUP;
831 return FALSE;
833 filename_to_ansi (lpFileName, filename_a);
834 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
835 pSecurityDescriptor));
839 static DWORD WINAPI
840 set_named_security_info (LPCTSTR lpObjectName,
841 SE_OBJECT_TYPE ObjectType,
842 SECURITY_INFORMATION SecurityInformation,
843 PSID psidOwner,
844 PSID psidGroup,
845 PACL pDacl,
846 PACL pSacl)
848 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
849 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
850 HMODULE hm_advapi32 = NULL;
851 if (is_windows_9x () == TRUE)
853 errno = ENOTSUP;
854 return ENOTSUP;
856 if (w32_unicode_filenames)
858 wchar_t filename_w[MAX_PATH];
860 if (g_b_init_set_named_security_info_w == 0)
862 g_b_init_set_named_security_info_w = 1;
863 hm_advapi32 = LoadLibrary ("Advapi32.dll");
864 s_pfn_Set_Named_Security_InfoW =
865 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
866 "SetNamedSecurityInfoW");
868 if (s_pfn_Set_Named_Security_InfoW == NULL)
870 errno = ENOTSUP;
871 return ENOTSUP;
873 filename_to_utf16 (lpObjectName, filename_w);
874 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
875 SecurityInformation, psidOwner,
876 psidGroup, pDacl, pSacl));
878 else
880 char filename_a[MAX_PATH];
882 if (g_b_init_set_named_security_info_a == 0)
884 g_b_init_set_named_security_info_a = 1;
885 hm_advapi32 = LoadLibrary ("Advapi32.dll");
886 s_pfn_Set_Named_Security_InfoA =
887 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
888 "SetNamedSecurityInfoA");
890 if (s_pfn_Set_Named_Security_InfoA == NULL)
892 errno = ENOTSUP;
893 return ENOTSUP;
895 filename_to_ansi (lpObjectName, filename_a);
896 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
897 SecurityInformation, psidOwner,
898 psidGroup, pDacl, pSacl));
902 static BOOL WINAPI
903 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
904 PSID *pOwner,
905 LPBOOL lpbOwnerDefaulted)
907 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
908 HMODULE hm_advapi32 = NULL;
909 if (is_windows_9x () == TRUE)
911 errno = ENOTSUP;
912 return FALSE;
914 if (g_b_init_get_security_descriptor_owner == 0)
916 g_b_init_get_security_descriptor_owner = 1;
917 hm_advapi32 = LoadLibrary ("Advapi32.dll");
918 s_pfn_Get_Security_Descriptor_Owner =
919 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
920 hm_advapi32, "GetSecurityDescriptorOwner");
922 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
924 errno = ENOTSUP;
925 return FALSE;
927 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
928 lpbOwnerDefaulted));
931 static BOOL WINAPI
932 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
933 PSID *pGroup,
934 LPBOOL lpbGroupDefaulted)
936 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
937 HMODULE hm_advapi32 = NULL;
938 if (is_windows_9x () == TRUE)
940 errno = ENOTSUP;
941 return FALSE;
943 if (g_b_init_get_security_descriptor_group == 0)
945 g_b_init_get_security_descriptor_group = 1;
946 hm_advapi32 = LoadLibrary ("Advapi32.dll");
947 s_pfn_Get_Security_Descriptor_Group =
948 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
949 hm_advapi32, "GetSecurityDescriptorGroup");
951 if (s_pfn_Get_Security_Descriptor_Group == NULL)
953 errno = ENOTSUP;
954 return FALSE;
956 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
957 lpbGroupDefaulted));
960 static BOOL WINAPI
961 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
962 LPBOOL lpbDaclPresent,
963 PACL *pDacl,
964 LPBOOL lpbDaclDefaulted)
966 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
967 HMODULE hm_advapi32 = NULL;
968 if (is_windows_9x () == TRUE)
970 errno = ENOTSUP;
971 return FALSE;
973 if (g_b_init_get_security_descriptor_dacl == 0)
975 g_b_init_get_security_descriptor_dacl = 1;
976 hm_advapi32 = LoadLibrary ("Advapi32.dll");
977 s_pfn_Get_Security_Descriptor_Dacl =
978 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
979 hm_advapi32, "GetSecurityDescriptorDacl");
981 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
983 errno = ENOTSUP;
984 return FALSE;
986 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
987 lpbDaclPresent, pDacl,
988 lpbDaclDefaulted));
991 static BOOL WINAPI
992 is_valid_sid (PSID sid)
994 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
995 HMODULE hm_advapi32 = NULL;
996 if (is_windows_9x () == TRUE)
998 return FALSE;
1000 if (g_b_init_is_valid_sid == 0)
1002 g_b_init_is_valid_sid = 1;
1003 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1004 s_pfn_Is_Valid_Sid =
1005 (IsValidSid_Proc) GetProcAddress (
1006 hm_advapi32, "IsValidSid");
1008 if (s_pfn_Is_Valid_Sid == NULL)
1010 return FALSE;
1012 return (s_pfn_Is_Valid_Sid (sid));
1015 static BOOL WINAPI
1016 equal_sid (PSID sid1, PSID sid2)
1018 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1019 HMODULE hm_advapi32 = NULL;
1020 if (is_windows_9x () == TRUE)
1022 return FALSE;
1024 if (g_b_init_equal_sid == 0)
1026 g_b_init_equal_sid = 1;
1027 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1028 s_pfn_Equal_Sid =
1029 (EqualSid_Proc) GetProcAddress (
1030 hm_advapi32, "EqualSid");
1032 if (s_pfn_Equal_Sid == NULL)
1034 return FALSE;
1036 return (s_pfn_Equal_Sid (sid1, sid2));
1039 static DWORD WINAPI
1040 get_length_sid (PSID sid)
1042 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1043 HMODULE hm_advapi32 = NULL;
1044 if (is_windows_9x () == TRUE)
1046 return 0;
1048 if (g_b_init_get_length_sid == 0)
1050 g_b_init_get_length_sid = 1;
1051 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1052 s_pfn_Get_Length_Sid =
1053 (GetLengthSid_Proc) GetProcAddress (
1054 hm_advapi32, "GetLengthSid");
1056 if (s_pfn_Get_Length_Sid == NULL)
1058 return 0;
1060 return (s_pfn_Get_Length_Sid (sid));
1063 static BOOL WINAPI
1064 copy_sid (DWORD destlen, PSID dest, PSID src)
1066 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1067 HMODULE hm_advapi32 = NULL;
1068 if (is_windows_9x () == TRUE)
1070 return FALSE;
1072 if (g_b_init_copy_sid == 0)
1074 g_b_init_copy_sid = 1;
1075 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1076 s_pfn_Copy_Sid =
1077 (CopySid_Proc) GetProcAddress (
1078 hm_advapi32, "CopySid");
1080 if (s_pfn_Copy_Sid == NULL)
1082 return FALSE;
1084 return (s_pfn_Copy_Sid (destlen, dest, src));
1088 END: Wrapper functions around OpenProcessToken
1089 and other functions in advapi32.dll that are only
1090 supported in Windows NT / 2k / XP
1093 static void WINAPI
1094 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1096 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1097 if (is_windows_9x () != TRUE)
1099 if (g_b_init_get_native_system_info == 0)
1101 g_b_init_get_native_system_info = 1;
1102 s_pfn_Get_Native_System_Info =
1103 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1104 "GetNativeSystemInfo");
1106 if (s_pfn_Get_Native_System_Info != NULL)
1107 s_pfn_Get_Native_System_Info (lpSystemInfo);
1109 else
1110 lpSystemInfo->dwNumberOfProcessors = -1;
1113 static BOOL WINAPI
1114 get_system_times (LPFILETIME lpIdleTime,
1115 LPFILETIME lpKernelTime,
1116 LPFILETIME lpUserTime)
1118 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1119 if (is_windows_9x () == TRUE)
1121 return FALSE;
1123 if (g_b_init_get_system_times == 0)
1125 g_b_init_get_system_times = 1;
1126 s_pfn_Get_System_times =
1127 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1128 "GetSystemTimes");
1130 if (s_pfn_Get_System_times == NULL)
1131 return FALSE;
1132 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1135 static BOOLEAN WINAPI
1136 create_symbolic_link (LPCSTR lpSymlinkFilename,
1137 LPCSTR lpTargetFileName,
1138 DWORD dwFlags)
1140 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1141 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1142 BOOLEAN retval;
1144 if (is_windows_9x () == TRUE)
1146 errno = ENOSYS;
1147 return 0;
1149 if (w32_unicode_filenames)
1151 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1153 if (g_b_init_create_symbolic_link_w == 0)
1155 g_b_init_create_symbolic_link_w = 1;
1156 s_pfn_Create_Symbolic_LinkW =
1157 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1158 "CreateSymbolicLinkW");
1160 if (s_pfn_Create_Symbolic_LinkW == NULL)
1162 errno = ENOSYS;
1163 return 0;
1166 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1167 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1168 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1169 /* If we were denied creation of the symlink, try again after
1170 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1171 if (!retval)
1173 TOKEN_PRIVILEGES priv_current;
1175 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1176 &priv_current))
1178 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1179 restore_privilege (&priv_current);
1180 revert_to_self ();
1184 else
1186 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1188 if (g_b_init_create_symbolic_link_a == 0)
1190 g_b_init_create_symbolic_link_a = 1;
1191 s_pfn_Create_Symbolic_LinkA =
1192 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1193 "CreateSymbolicLinkA");
1195 if (s_pfn_Create_Symbolic_LinkA == NULL)
1197 errno = ENOSYS;
1198 return 0;
1201 filename_to_ansi (lpSymlinkFilename, symfn_a);
1202 filename_to_ansi (lpTargetFileName, tgtfn_a);
1203 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1204 /* If we were denied creation of the symlink, try again after
1205 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1206 if (!retval)
1208 TOKEN_PRIVILEGES priv_current;
1210 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1211 &priv_current))
1213 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1214 restore_privilege (&priv_current);
1215 revert_to_self ();
1219 return retval;
1222 static BOOL WINAPI
1223 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1225 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1227 if (is_windows_9x () == TRUE)
1229 errno = ENOTSUP;
1230 return FALSE;
1233 if (g_b_init_is_valid_security_descriptor == 0)
1235 g_b_init_is_valid_security_descriptor = 1;
1236 s_pfn_Is_Valid_Security_Descriptor_Proc =
1237 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1238 "IsValidSecurityDescriptor");
1240 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1242 errno = ENOTSUP;
1243 return FALSE;
1246 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1249 static BOOL WINAPI
1250 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1251 DWORD RequestedStringSDRevision,
1252 SECURITY_INFORMATION SecurityInformation,
1253 LPTSTR *StringSecurityDescriptor,
1254 PULONG StringSecurityDescriptorLen)
1256 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1257 BOOL retval;
1259 if (is_windows_9x () == TRUE)
1261 errno = ENOTSUP;
1262 return FALSE;
1265 if (g_b_init_convert_sd_to_sddl == 0)
1267 g_b_init_convert_sd_to_sddl = 1;
1268 #ifdef _UNICODE
1269 s_pfn_Convert_SD_To_SDDL =
1270 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1271 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1272 #else
1273 s_pfn_Convert_SD_To_SDDL =
1274 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1275 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1276 #endif
1278 if (s_pfn_Convert_SD_To_SDDL == NULL)
1280 errno = ENOTSUP;
1281 return FALSE;
1284 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1285 RequestedStringSDRevision,
1286 SecurityInformation,
1287 StringSecurityDescriptor,
1288 StringSecurityDescriptorLen);
1290 return retval;
1293 static BOOL WINAPI
1294 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1295 DWORD StringSDRevision,
1296 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1297 PULONG SecurityDescriptorSize)
1299 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1300 BOOL retval;
1302 if (is_windows_9x () == TRUE)
1304 errno = ENOTSUP;
1305 return FALSE;
1308 if (g_b_init_convert_sddl_to_sd == 0)
1310 g_b_init_convert_sddl_to_sd = 1;
1311 #ifdef _UNICODE
1312 s_pfn_Convert_SDDL_To_SD =
1313 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1314 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1315 #else
1316 s_pfn_Convert_SDDL_To_SD =
1317 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1318 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1319 #endif
1321 if (s_pfn_Convert_SDDL_To_SD == NULL)
1323 errno = ENOTSUP;
1324 return FALSE;
1327 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1328 StringSDRevision,
1329 SecurityDescriptor,
1330 SecurityDescriptorSize);
1332 return retval;
1335 static DWORD WINAPI
1336 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1338 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1339 HMODULE hm_iphlpapi = NULL;
1341 if (is_windows_9x () == TRUE)
1342 return ERROR_NOT_SUPPORTED;
1344 if (g_b_init_get_adapters_info == 0)
1346 g_b_init_get_adapters_info = 1;
1347 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1348 if (hm_iphlpapi)
1349 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1350 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1352 if (s_pfn_Get_Adapters_Info == NULL)
1353 return ERROR_NOT_SUPPORTED;
1354 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1359 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1360 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1362 This is called from alloc.c:valid_pointer_p. */
1364 w32_valid_pointer_p (void *p, int size)
1366 SIZE_T done;
1367 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1369 if (h)
1371 unsigned char *buf = alloca (size);
1372 int retval = ReadProcessMemory (h, p, buf, size, &done);
1374 CloseHandle (h);
1375 return retval;
1377 else
1378 return -1;
1383 /* Here's an overview of how the Windows build supports file names
1384 that cannot be encoded by the current system codepage.
1386 From the POV of Lisp and layers of C code above the functions here,
1387 Emacs on Windows pretends that its file names are encoded in UTF-8;
1388 see encode_file and decode_file on coding.c. Any file name that is
1389 passed as a unibyte string to C functions defined here is assumed
1390 to be in UTF-8 encoding. Any file name returned by functions
1391 defined here must be in UTF-8 encoding, with only a few exceptions
1392 reserved for a couple of special cases. (Be sure to use
1393 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1394 as they can be much longer than MAX_PATH!)
1396 The UTF-8 encoded file names cannot be passed to system APIs, as
1397 Windows does not support that. Therefore, they are converted
1398 either to UTF-16 or to the ANSI codepage, depending on the value of
1399 w32-unicode-filenames, before calling any system APIs or CRT library
1400 functions. The default value of that variable is determined by the
1401 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1402 user can change that default (although I don't see why would she
1403 want to).
1405 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1406 filename_from_utf16, and filename_from_ansi, are the workhorses of
1407 these conversions. They rely on Windows native APIs
1408 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1409 functions from coding.c here, because they allocate memory, which
1410 is a bad idea on the level of libc, which is what the functions
1411 here emulate. (If you worry about performance due to constant
1412 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1413 it was measured to take only a few microseconds on a not-so-fast
1414 machine, and second, that's exactly what the ANSI APIs we used
1415 before did anyway, because they are just thin wrappers around the
1416 Unicode APIs.)
1418 The variables file-name-coding-system and default-file-name-coding-system
1419 still exist, but are actually used only when a file name needs to
1420 be converted to the ANSI codepage. This happens all the time when
1421 w32-unicode-filenames is nil, but can also happen from time to time
1422 when it is t. Otherwise, these variables have no effect on file-name
1423 encoding when w32-unicode-filenames is t; this is similar to
1424 selection-coding-system.
1426 This arrangement works very well, but it has a few gotchas and
1427 limitations:
1429 . Lisp code that encodes or decodes file names manually should
1430 normally use 'utf-8' as the coding-system on Windows,
1431 disregarding file-name-coding-system. This is a somewhat
1432 unpleasant consequence, but it cannot be avoided. Fortunately,
1433 very few Lisp packages need to do that.
1435 More generally, passing to library functions (e.g., fopen or
1436 opendir) file names already encoded in the ANSI codepage is
1437 explicitly *verboten*, as all those functions, as shadowed and
1438 emulated here, assume they will receive UTF-8 encoded file names.
1440 For the same reasons, no CRT function or Win32 API can be called
1441 directly in Emacs sources, without either converting the file
1442 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1443 some shadowing function defined here.
1445 . Environment variables stored in Vprocess_environment are encoded
1446 in the ANSI codepage, so if getenv/egetenv is used for a variable
1447 whose value is a file name or a list of directories, it needs to
1448 be converted to UTF-8, before it is used as argument to functions
1449 or decoded into a Lisp string.
1451 . File names passed to external libraries, like the image libraries
1452 and GnuTLS, need special handling. These libraries generally
1453 don't support UTF-16 or UTF-8 file names, so they must get file
1454 names encoded in the ANSI codepage. To facilitate using these
1455 libraries with file names that are not encodable in the ANSI
1456 codepage, use the function ansi_encode_filename, which will try
1457 to use the short 8+3 alias of a file name if that file name is
1458 not encodable in the ANSI codepage. See image.c and gnutls.c for
1459 examples of how this should be done.
1461 . Running subprocesses in non-ASCII directories and with non-ASCII
1462 file arguments is limited to the current codepage (even though
1463 Emacs is perfectly capable of finding an executable program file
1464 in a directory whose name cannot be encoded in the current
1465 codepage). This is because the command-line arguments are
1466 encoded _before_ they get to the w32-specific level, and the
1467 encoding is not known in advance (it doesn't have to be the
1468 current ANSI codepage), so w32proc.c functions cannot re-encode
1469 them in UTF-16. This should be fixed, but will also require
1470 changes in cmdproxy. The current limitation is not terribly bad
1471 anyway, since very few, if any, Windows console programs that are
1472 likely to be invoked by Emacs support UTF-16 encoded command
1473 lines.
1475 . For similar reasons, server.el and emacsclient are also limited
1476 to the current ANSI codepage for now.
1478 . Emacs itself can only handle command-line arguments encoded in
1479 the current codepage.
1481 . Turning on w32-unicode-filename on Windows 9X (if it at all
1482 works) requires UNICOWS.DLL, which is thus a requirement even in
1483 non-GUI sessions, something the we previously avoided. */
1487 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1488 codepage defined by file-name-coding-system. */
1490 /* Current codepage for encoding file names. */
1491 static int file_name_codepage;
1493 /* Produce a Windows ANSI codepage suitable for encoding file names.
1494 Return the information about that codepage in CP_INFO. */
1496 codepage_for_filenames (CPINFO *cp_info)
1498 /* A simple cache to avoid calling GetCPInfo every time we need to
1499 encode/decode a file name. The file-name encoding is not
1500 supposed to be changed too frequently, if ever. */
1501 static Lisp_Object last_file_name_encoding;
1502 static CPINFO cp;
1503 Lisp_Object current_encoding;
1505 current_encoding = Vfile_name_coding_system;
1506 if (NILP (current_encoding))
1507 current_encoding = Vdefault_file_name_coding_system;
1509 if (!EQ (last_file_name_encoding, current_encoding))
1511 /* Default to the current ANSI codepage. */
1512 file_name_codepage = w32_ansi_code_page;
1514 if (NILP (current_encoding))
1516 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1517 char *cp = NULL, *end;
1518 int cpnum;
1520 if (strncmp (cpname, "cp", 2) == 0)
1521 cp = cpname + 2;
1522 else if (strncmp (cpname, "windows-", 8) == 0)
1523 cp = cpname + 8;
1525 if (cp)
1527 end = cp;
1528 cpnum = strtol (cp, &end, 10);
1529 if (cpnum && *end == '\0' && end - cp >= 2)
1530 file_name_codepage = cpnum;
1534 if (!file_name_codepage)
1535 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1537 if (!GetCPInfo (file_name_codepage, &cp))
1539 file_name_codepage = CP_ACP;
1540 if (!GetCPInfo (file_name_codepage, &cp))
1541 emacs_abort ();
1544 if (cp_info)
1545 *cp_info = cp;
1547 return file_name_codepage;
1551 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1553 int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1554 fn_out, MAX_PATH);
1556 if (!result)
1558 DWORD err = GetLastError ();
1560 switch (err)
1562 case ERROR_INVALID_FLAGS:
1563 case ERROR_INVALID_PARAMETER:
1564 errno = EINVAL;
1565 break;
1566 case ERROR_INSUFFICIENT_BUFFER:
1567 case ERROR_NO_UNICODE_TRANSLATION:
1568 default:
1569 errno = ENOENT;
1570 break;
1572 return -1;
1574 return 0;
1578 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1580 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1581 fn_out, MAX_UTF8_PATH, NULL, NULL);
1583 if (!result)
1585 DWORD err = GetLastError ();
1587 switch (err)
1589 case ERROR_INVALID_FLAGS:
1590 case ERROR_INVALID_PARAMETER:
1591 errno = EINVAL;
1592 break;
1593 case ERROR_INSUFFICIENT_BUFFER:
1594 case ERROR_NO_UNICODE_TRANSLATION:
1595 default:
1596 errno = ENOENT;
1597 break;
1599 return -1;
1601 return 0;
1605 filename_to_ansi (const char *fn_in, char *fn_out)
1607 wchar_t fn_utf16[MAX_PATH];
1609 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1611 int result;
1612 int codepage = codepage_for_filenames (NULL);
1614 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1615 fn_out, MAX_PATH, NULL, NULL);
1616 if (!result)
1618 DWORD err = GetLastError ();
1620 switch (err)
1622 case ERROR_INVALID_FLAGS:
1623 case ERROR_INVALID_PARAMETER:
1624 errno = EINVAL;
1625 break;
1626 case ERROR_INSUFFICIENT_BUFFER:
1627 case ERROR_NO_UNICODE_TRANSLATION:
1628 default:
1629 errno = ENOENT;
1630 break;
1632 return -1;
1634 return 0;
1636 return -1;
1640 filename_from_ansi (const char *fn_in, char *fn_out)
1642 wchar_t fn_utf16[MAX_PATH];
1643 int codepage = codepage_for_filenames (NULL);
1644 int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1645 fn_utf16, MAX_PATH);
1647 if (!result)
1649 DWORD err = GetLastError ();
1651 switch (err)
1653 case ERROR_INVALID_FLAGS:
1654 case ERROR_INVALID_PARAMETER:
1655 errno = EINVAL;
1656 break;
1657 case ERROR_INSUFFICIENT_BUFFER:
1658 case ERROR_NO_UNICODE_TRANSLATION:
1659 default:
1660 errno = ENOENT;
1661 break;
1663 return -1;
1665 return filename_from_utf16 (fn_utf16, fn_out);
1670 /* The directory where we started, in UTF-8. */
1671 static char startup_dir[MAX_UTF8_PATH];
1673 /* Get the current working directory. */
1674 char *
1675 getcwd (char *dir, int dirsize)
1677 if (!dirsize)
1679 errno = EINVAL;
1680 return NULL;
1682 if (dirsize <= strlen (startup_dir))
1684 errno = ERANGE;
1685 return NULL;
1687 #if 0
1688 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1689 return dir;
1690 return NULL;
1691 #else
1692 /* Emacs doesn't actually change directory itself, it stays in the
1693 same directory where it was started. */
1694 strcpy (dir, startup_dir);
1695 return dir;
1696 #endif
1699 /* Emulate getloadavg. */
1701 struct load_sample {
1702 time_t sample_time;
1703 ULONGLONG idle;
1704 ULONGLONG kernel;
1705 ULONGLONG user;
1708 /* Number of processors on this machine. */
1709 static unsigned num_of_processors;
1711 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1712 static struct load_sample samples[16*60];
1713 static int first_idx = -1, last_idx = -1;
1714 static int max_idx = ARRAYELTS (samples);
1716 static int
1717 buf_next (int from)
1719 int next_idx = from + 1;
1721 if (next_idx >= max_idx)
1722 next_idx = 0;
1724 return next_idx;
1727 static int
1728 buf_prev (int from)
1730 int prev_idx = from - 1;
1732 if (prev_idx < 0)
1733 prev_idx = max_idx - 1;
1735 return prev_idx;
1738 static void
1739 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1741 SYSTEM_INFO sysinfo;
1742 FILETIME ft_idle, ft_user, ft_kernel;
1744 /* Initialize the number of processors on this machine. */
1745 if (num_of_processors <= 0)
1747 get_native_system_info (&sysinfo);
1748 num_of_processors = sysinfo.dwNumberOfProcessors;
1749 if (num_of_processors <= 0)
1751 GetSystemInfo (&sysinfo);
1752 num_of_processors = sysinfo.dwNumberOfProcessors;
1754 if (num_of_processors <= 0)
1755 num_of_processors = 1;
1758 /* TODO: Take into account threads that are ready to run, by
1759 sampling the "\System\Processor Queue Length" performance
1760 counter. The code below accounts only for threads that are
1761 actually running. */
1763 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1765 ULARGE_INTEGER uidle, ukernel, uuser;
1767 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1768 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1769 memcpy (&uuser, &ft_user, sizeof (ft_user));
1770 *idle = uidle.QuadPart;
1771 *kernel = ukernel.QuadPart;
1772 *user = uuser.QuadPart;
1774 else
1776 *idle = 0;
1777 *kernel = 0;
1778 *user = 0;
1782 /* Produce the load average for a given time interval, using the
1783 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1784 1-minute, 5-minute, or 15-minute average, respectively. */
1785 static double
1786 getavg (int which)
1788 double retval = -1.0;
1789 double tdiff;
1790 int idx;
1791 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1792 time_t now = samples[last_idx].sample_time;
1794 if (first_idx != last_idx)
1796 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1798 tdiff = difftime (now, samples[idx].sample_time);
1799 if (tdiff >= span - 2*DBL_EPSILON*now)
1801 long double sys =
1802 samples[last_idx].kernel + samples[last_idx].user
1803 - (samples[idx].kernel + samples[idx].user);
1804 long double idl = samples[last_idx].idle - samples[idx].idle;
1806 retval = (1.0 - idl / sys) * num_of_processors;
1807 break;
1809 if (idx == first_idx)
1810 break;
1814 return retval;
1818 getloadavg (double loadavg[], int nelem)
1820 int elem;
1821 ULONGLONG idle, kernel, user;
1822 time_t now = time (NULL);
1824 /* If system time jumped back for some reason, delete all samples
1825 whose time is later than the current wall-clock time. This
1826 prevents load average figures from becoming frozen for prolonged
1827 periods of time, when system time is reset backwards. */
1828 if (last_idx >= 0)
1830 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1832 if (last_idx == first_idx)
1834 first_idx = last_idx = -1;
1835 break;
1837 last_idx = buf_prev (last_idx);
1841 /* Store another sample. We ignore samples that are less than 1 sec
1842 apart. */
1843 if (last_idx < 0
1844 || (difftime (now, samples[last_idx].sample_time)
1845 >= 1.0 - 2*DBL_EPSILON*now))
1847 sample_system_load (&idle, &kernel, &user);
1848 last_idx = buf_next (last_idx);
1849 samples[last_idx].sample_time = now;
1850 samples[last_idx].idle = idle;
1851 samples[last_idx].kernel = kernel;
1852 samples[last_idx].user = user;
1853 /* If the buffer has more that 15 min worth of samples, discard
1854 the old ones. */
1855 if (first_idx == -1)
1856 first_idx = last_idx;
1857 while (first_idx != last_idx
1858 && (difftime (now, samples[first_idx].sample_time)
1859 >= 15.0*60 + 2*DBL_EPSILON*now))
1860 first_idx = buf_next (first_idx);
1863 for (elem = 0; elem < nelem; elem++)
1865 double avg = getavg (elem);
1867 if (avg < 0)
1868 break;
1869 loadavg[elem] = avg;
1872 return elem;
1875 /* Emulate getpwuid, getpwnam and others. */
1877 #define PASSWD_FIELD_SIZE 256
1879 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1880 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1881 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1882 static char dflt_passwd_dir[MAX_UTF8_PATH];
1883 static char dflt_passwd_shell[MAX_UTF8_PATH];
1885 static struct passwd dflt_passwd =
1887 dflt_passwd_name,
1888 dflt_passwd_passwd,
1892 dflt_passwd_gecos,
1893 dflt_passwd_dir,
1894 dflt_passwd_shell,
1897 static char dflt_group_name[GNLEN+1];
1899 static struct group dflt_group =
1901 /* When group information is not available, we return this as the
1902 group for all files. */
1903 dflt_group_name,
1907 unsigned
1908 getuid (void)
1910 return dflt_passwd.pw_uid;
1913 unsigned
1914 geteuid (void)
1916 /* I could imagine arguing for checking to see whether the user is
1917 in the Administrators group and returning a UID of 0 for that
1918 case, but I don't know how wise that would be in the long run. */
1919 return getuid ();
1922 unsigned
1923 getgid (void)
1925 return dflt_passwd.pw_gid;
1928 unsigned
1929 getegid (void)
1931 return getgid ();
1934 struct passwd *
1935 getpwuid (unsigned uid)
1937 if (uid == dflt_passwd.pw_uid)
1938 return &dflt_passwd;
1939 return NULL;
1942 struct group *
1943 getgrgid (gid_t gid)
1945 return &dflt_group;
1948 struct passwd *
1949 getpwnam (char *name)
1951 struct passwd *pw;
1953 pw = getpwuid (getuid ());
1954 if (!pw)
1955 return pw;
1957 if (xstrcasecmp (name, pw->pw_name))
1958 return NULL;
1960 return pw;
1963 static void
1964 init_user_info (void)
1966 /* Find the user's real name by opening the process token and
1967 looking up the name associated with the user-sid in that token.
1969 Use the relative portion of the identifier authority value from
1970 the user-sid as the user id value (same for group id using the
1971 primary group sid from the process token). */
1973 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1974 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1975 DWORD glength = sizeof (gname);
1976 HANDLE token = NULL;
1977 SID_NAME_USE user_type;
1978 unsigned char *buf = NULL;
1979 DWORD blen = 0;
1980 TOKEN_USER user_token;
1981 TOKEN_PRIMARY_GROUP group_token;
1982 BOOL result;
1984 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1985 if (result)
1987 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1988 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1990 buf = xmalloc (blen);
1991 result = get_token_information (token, TokenUser,
1992 (LPVOID)buf, blen, &needed);
1993 if (result)
1995 memcpy (&user_token, buf, sizeof (user_token));
1996 result = lookup_account_sid (NULL, user_token.User.Sid,
1997 uname, &ulength,
1998 domain, &dlength, &user_type);
2001 else
2002 result = FALSE;
2004 if (result)
2006 strcpy (dflt_passwd.pw_name, uname);
2007 /* Determine a reasonable uid value. */
2008 if (xstrcasecmp ("administrator", uname) == 0)
2010 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2011 dflt_passwd.pw_gid = 513; /* well-known None gid */
2013 else
2015 /* Use the last sub-authority value of the RID, the relative
2016 portion of the SID, as user/group ID. */
2017 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2019 /* Get group id and name. */
2020 result = get_token_information (token, TokenPrimaryGroup,
2021 (LPVOID)buf, blen, &needed);
2022 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2024 buf = xrealloc (buf, blen = needed);
2025 result = get_token_information (token, TokenPrimaryGroup,
2026 (LPVOID)buf, blen, &needed);
2028 if (result)
2030 memcpy (&group_token, buf, sizeof (group_token));
2031 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2032 dlength = sizeof (domain);
2033 /* If we can get at the real Primary Group name, use that.
2034 Otherwise, the default group name was already set to
2035 "None" in globals_of_w32. */
2036 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2037 gname, &glength, NULL, &dlength,
2038 &user_type))
2039 strcpy (dflt_group_name, gname);
2041 else
2042 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2045 /* If security calls are not supported (presumably because we
2046 are running under Windows 9X), fallback to this: */
2047 else if (GetUserName (uname, &ulength))
2049 strcpy (dflt_passwd.pw_name, uname);
2050 if (xstrcasecmp ("administrator", uname) == 0)
2051 dflt_passwd.pw_uid = 0;
2052 else
2053 dflt_passwd.pw_uid = 123;
2054 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2056 else
2058 strcpy (dflt_passwd.pw_name, "unknown");
2059 dflt_passwd.pw_uid = 123;
2060 dflt_passwd.pw_gid = 123;
2062 dflt_group.gr_gid = dflt_passwd.pw_gid;
2064 /* Set dir and shell from environment variables. */
2065 if (w32_unicode_filenames)
2067 wchar_t *home = _wgetenv (L"HOME");
2068 wchar_t *shell = _wgetenv (L"SHELL");
2070 /* Ensure HOME and SHELL are defined. */
2071 if (home == NULL)
2072 emacs_abort ();
2073 if (shell == NULL)
2074 emacs_abort ();
2075 filename_from_utf16 (home, dflt_passwd.pw_dir);
2076 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2078 else
2080 char *home = getenv ("HOME");
2081 char *shell = getenv ("SHELL");
2083 if (home == NULL)
2084 emacs_abort ();
2085 if (shell == NULL)
2086 emacs_abort ();
2087 filename_from_ansi (home, dflt_passwd.pw_dir);
2088 filename_from_ansi (shell, dflt_passwd.pw_shell);
2091 xfree (buf);
2092 if (token)
2093 CloseHandle (token);
2097 random (void)
2099 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2100 return ((rand () << 15) | rand ());
2103 void
2104 srandom (int seed)
2106 srand (seed);
2109 /* Return the maximum length in bytes of a multibyte character
2110 sequence encoded in the current ANSI codepage. This is required to
2111 correctly walk the encoded file names one character at a time. */
2112 static int
2113 max_filename_mbslen (void)
2115 CPINFO cp_info;
2117 codepage_for_filenames (&cp_info);
2118 return cp_info.MaxCharSize;
2121 /* Normalize filename by converting in-place all of its path
2122 separators to the separator specified by PATH_SEP. */
2124 static void
2125 normalize_filename (register char *fp, char path_sep)
2127 char *p2;
2129 /* Always lower-case drive letters a-z, even if the filesystem
2130 preserves case in filenames.
2131 This is so filenames can be compared by string comparison
2132 functions that are case-sensitive. Even case-preserving filesystems
2133 do not distinguish case in drive letters. */
2134 p2 = fp + 1;
2136 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2138 *fp += 'a' - 'A';
2139 fp += 2;
2142 while (*fp)
2144 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2145 *fp = path_sep;
2146 fp++;
2150 /* Destructively turn backslashes into slashes. */
2151 void
2152 dostounix_filename (register char *p)
2154 normalize_filename (p, '/');
2157 /* Destructively turn slashes into backslashes. */
2158 void
2159 unixtodos_filename (register char *p)
2161 normalize_filename (p, '\\');
2164 /* Remove all CR's that are followed by a LF.
2165 (From msdos.c...probably should figure out a way to share it,
2166 although this code isn't going to ever change.) */
2167 static int
2168 crlf_to_lf (register int n, register unsigned char *buf)
2170 unsigned char *np = buf;
2171 unsigned char *startp = buf;
2172 unsigned char *endp = buf + n;
2174 if (n == 0)
2175 return n;
2176 while (buf < endp - 1)
2178 if (*buf == 0x0d)
2180 if (*(++buf) != 0x0a)
2181 *np++ = 0x0d;
2183 else
2184 *np++ = *buf++;
2186 if (buf < endp)
2187 *np++ = *buf++;
2188 return np - startp;
2191 /* Parse the root part of file name, if present. Return length and
2192 optionally store pointer to char after root. */
2193 static int
2194 parse_root (const char * name, const char ** pPath)
2196 const char * start = name;
2198 if (name == NULL)
2199 return 0;
2201 /* find the root name of the volume if given */
2202 if (isalpha (name[0]) && name[1] == ':')
2204 /* skip past drive specifier */
2205 name += 2;
2206 if (IS_DIRECTORY_SEP (name[0]))
2207 name++;
2209 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2211 int slashes = 2;
2213 name += 2;
2216 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2217 break;
2218 name++;
2220 while ( *name );
2221 if (IS_DIRECTORY_SEP (name[0]))
2222 name++;
2225 if (pPath)
2226 *pPath = name;
2228 return name - start;
2231 /* Get long base name for name; name is assumed to be absolute. */
2232 static int
2233 get_long_basename (char * name, char * buf, int size)
2235 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2236 char fname_utf8[MAX_UTF8_PATH];
2237 int len = 0;
2238 int cstatus = -1;
2240 /* Must be valid filename, no wild cards or other invalid characters. */
2241 if (strpbrk (name, "*?|<>\""))
2242 return 0;
2244 if (w32_unicode_filenames)
2246 wchar_t fname_utf16[MAX_PATH];
2247 WIN32_FIND_DATAW find_data_wide;
2249 filename_to_utf16 (name, fname_utf16);
2250 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2251 if (dir_handle != INVALID_HANDLE_VALUE)
2252 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2254 else
2256 char fname_ansi[MAX_PATH];
2257 WIN32_FIND_DATAA find_data_ansi;
2259 filename_to_ansi (name, fname_ansi);
2260 /* If the ANSI name includes ? characters, it is not encodable
2261 in the ANSI codepage. In that case, we deliver the question
2262 marks to the caller; calling FindFirstFileA in this case
2263 could return some unrelated file name in the same
2264 directory. */
2265 if (_mbspbrk (fname_ansi, "?"))
2267 /* Find the basename of fname_ansi. */
2268 char *p = strrchr (fname_ansi, '\\');
2270 if (!p)
2271 p = fname_ansi;
2272 else
2273 p++;
2274 cstatus = filename_from_ansi (p, fname_utf8);
2276 else
2278 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2279 if (dir_handle != INVALID_HANDLE_VALUE)
2280 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2284 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2285 memcpy (buf, fname_utf8, len + 1);
2286 else
2287 len = 0;
2289 if (dir_handle != INVALID_HANDLE_VALUE)
2290 FindClose (dir_handle);
2292 return len;
2295 /* Get long name for file, if possible (assumed to be absolute). */
2296 BOOL
2297 w32_get_long_filename (const char * name, char * buf, int size)
2299 char * o = buf;
2300 char * p;
2301 const char * q;
2302 char full[ MAX_UTF8_PATH ];
2303 int len;
2305 len = strlen (name);
2306 if (len >= MAX_UTF8_PATH)
2307 return FALSE;
2309 /* Use local copy for destructive modification. */
2310 memcpy (full, name, len+1);
2311 unixtodos_filename (full);
2313 /* Copy root part verbatim. */
2314 len = parse_root (full, (const char **)&p);
2315 memcpy (o, full, len);
2316 o += len;
2317 *o = '\0';
2318 size -= len;
2320 while (p != NULL && *p)
2322 q = p;
2323 p = strchr (q, '\\');
2324 if (p) *p = '\0';
2325 len = get_long_basename (full, o, size);
2326 if (len > 0)
2328 o += len;
2329 size -= len;
2330 if (p != NULL)
2332 *p++ = '\\';
2333 if (size < 2)
2334 return FALSE;
2335 *o++ = '\\';
2336 size--;
2337 *o = '\0';
2340 else
2341 return FALSE;
2344 return TRUE;
2347 unsigned int
2348 w32_get_short_filename (const char * name, char * buf, int size)
2350 if (w32_unicode_filenames)
2352 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2353 unsigned int retval;
2355 filename_to_utf16 (name, name_utf16);
2356 retval = GetShortPathNameW (name_utf16, short_name, size);
2357 if (retval && retval < size)
2358 filename_from_utf16 (short_name, buf);
2359 return retval;
2361 else
2363 char name_ansi[MAX_PATH];
2365 filename_to_ansi (name, name_ansi);
2366 return GetShortPathNameA (name_ansi, buf, size);
2370 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2371 MS-Windows ANSI codepage. If FILENAME includes characters not
2372 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2373 if it exists. This is needed because the w32 build wants to
2374 support file names outside of the system locale, but image
2375 libraries typically don't support wide (a.k.a. "Unicode") APIs
2376 required for that. */
2378 Lisp_Object
2379 ansi_encode_filename (Lisp_Object filename)
2381 Lisp_Object encoded_filename;
2382 char fname[MAX_PATH];
2384 filename_to_ansi (SSDATA (filename), fname);
2385 if (_mbspbrk (fname, "?"))
2387 char shortname[MAX_PATH];
2389 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2391 dostounix_filename (shortname);
2392 encoded_filename = build_string (shortname);
2394 else
2395 encoded_filename = build_unibyte_string (fname);
2397 else
2398 encoded_filename = build_unibyte_string (fname);
2399 return encoded_filename;
2402 static int
2403 is_unc_volume (const char *filename)
2405 const char *ptr = filename;
2407 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2408 return 0;
2410 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2411 return 0;
2413 return 1;
2416 /* Emulate the Posix unsetenv. */
2418 unsetenv (const char *name)
2420 char *var;
2421 size_t name_len;
2423 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2425 errno = EINVAL;
2426 return -1;
2428 name_len = strlen (name);
2429 /* MS docs says an environment variable cannot be longer than 32K. */
2430 if (name_len > 32767)
2432 errno = ENOMEM;
2433 return 0;
2435 /* It is safe to use 'alloca' with 32K size, since the stack is at
2436 least 2MB, and we set it to 8MB in the link command line. */
2437 var = alloca (name_len + 2);
2438 strncpy (var, name, name_len);
2439 var[name_len++] = '=';
2440 var[name_len] = '\0';
2441 return _putenv (var);
2444 /* MS _putenv doesn't support removing a variable when the argument
2445 does not include the '=' character, so we fix that here. */
2447 sys_putenv (char *str)
2449 const char *const name_end = strchr (str, '=');
2451 if (name_end == NULL)
2453 /* Remove the variable from the environment. */
2454 return unsetenv (str);
2457 return _putenv (str);
2460 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2462 LPBYTE
2463 w32_get_resource (char *key, LPDWORD lpdwtype)
2465 LPBYTE lpvalue;
2466 HKEY hrootkey = NULL;
2467 DWORD cbData;
2469 /* Check both the current user and the local machine to see if
2470 we have any resources. */
2472 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2474 lpvalue = NULL;
2476 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2477 && (lpvalue = xmalloc (cbData)) != NULL
2478 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2480 RegCloseKey (hrootkey);
2481 return (lpvalue);
2484 xfree (lpvalue);
2486 RegCloseKey (hrootkey);
2489 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2491 lpvalue = NULL;
2493 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2494 && (lpvalue = xmalloc (cbData)) != NULL
2495 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2497 RegCloseKey (hrootkey);
2498 return (lpvalue);
2501 xfree (lpvalue);
2503 RegCloseKey (hrootkey);
2506 return (NULL);
2509 /* The argv[] array holds ANSI-encoded strings, and so this function
2510 works with ANS_encoded strings. */
2511 void
2512 init_environment (char ** argv)
2514 static const char * const tempdirs[] = {
2515 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2518 int i;
2520 const int imax = ARRAYELTS (tempdirs);
2522 /* Implementation note: This function explicitly works with ANSI
2523 file names, not with UTF-8 encoded file names. This is because
2524 this function pushes variables into the Emacs's environment, and
2525 the environment variables are always assumed to be in the
2526 locale-specific encoding. Do NOT call any functions that accept
2527 UTF-8 file names from this function! */
2529 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2530 temporary files and assume "/tmp" if $TMPDIR is unset, which
2531 will break on DOS/Windows. Refuse to work if we cannot find
2532 a directory, not even "c:/", usable for that purpose. */
2533 for (i = 0; i < imax ; i++)
2535 const char *tmp = tempdirs[i];
2537 if (*tmp == '$')
2538 tmp = getenv (tmp + 1);
2539 /* Note that `access' can lie to us if the directory resides on a
2540 read-only filesystem, like CD-ROM or a write-protected floppy.
2541 The only way to be really sure is to actually create a file and
2542 see if it succeeds. But I think that's too much to ask. */
2544 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2545 if (tmp && sys_access (tmp, D_OK) == 0)
2547 char * var = alloca (strlen (tmp) + 8);
2548 sprintf (var, "TMPDIR=%s", tmp);
2549 _putenv (strdup (var));
2550 break;
2553 if (i >= imax)
2554 cmd_error_internal
2555 (Fcons (Qerror,
2556 Fcons (build_string ("no usable temporary directories found!!"),
2557 Qnil)),
2558 "While setting TMPDIR: ");
2560 /* Check for environment variables and use registry settings if they
2561 don't exist. Fallback on default values where applicable. */
2563 int i;
2564 LPBYTE lpval;
2565 DWORD dwType;
2566 char locale_name[32];
2567 char default_home[MAX_PATH];
2568 int appdata = 0;
2570 static const struct env_entry
2572 char * name;
2573 char * def_value;
2574 } dflt_envvars[] =
2576 /* If the default value is NULL, we will use the value from the
2577 outside environment or the Registry, but will not push the
2578 variable into the Emacs environment if it is defined neither
2579 in the Registry nor in the outside environment. */
2580 {"HOME", "C:/"},
2581 {"PRELOAD_WINSOCK", NULL},
2582 {"emacs_dir", "C:/emacs"},
2583 {"EMACSLOADPATH", NULL},
2584 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2585 {"EMACSDATA", NULL},
2586 {"EMACSPATH", NULL},
2587 {"INFOPATH", NULL},
2588 {"EMACSDOC", NULL},
2589 {"TERM", "cmd"},
2590 {"LANG", NULL},
2593 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2595 /* We need to copy dflt_envvars[] and work on the copy because we
2596 don't want the dumped Emacs to inherit the values of
2597 environment variables we saw during dumping (which could be on
2598 a different system). The defaults above must be left intact. */
2599 struct env_entry env_vars[N_ENV_VARS];
2601 for (i = 0; i < N_ENV_VARS; i++)
2602 env_vars[i] = dflt_envvars[i];
2604 /* For backwards compatibility, check if a .emacs file exists in C:/
2605 If not, then we can try to default to the appdata directory under the
2606 user's profile, which is more likely to be writable. */
2607 if (sys_access ("C:/.emacs", F_OK) != 0)
2609 HRESULT profile_result;
2610 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2611 of Windows 95 and NT4 that have not been updated to include
2612 MSIE 5. */
2613 ShGetFolderPath_fn get_folder_path;
2614 get_folder_path = (ShGetFolderPath_fn)
2615 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2617 if (get_folder_path != NULL)
2619 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2620 0, default_home);
2622 /* If we can't get the appdata dir, revert to old behavior. */
2623 if (profile_result == S_OK)
2625 env_vars[0].def_value = default_home;
2626 appdata = 1;
2631 /* Get default locale info and use it for LANG. */
2632 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2633 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2634 locale_name, sizeof (locale_name)))
2636 for (i = 0; i < N_ENV_VARS; i++)
2638 if (strcmp (env_vars[i].name, "LANG") == 0)
2640 env_vars[i].def_value = locale_name;
2641 break;
2646 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2648 /* Treat emacs_dir specially: set it unconditionally based on our
2649 location. */
2651 char *p;
2652 char modname[MAX_PATH];
2654 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2655 emacs_abort ();
2656 if ((p = _mbsrchr (modname, '\\')) == NULL)
2657 emacs_abort ();
2658 *p = 0;
2660 if ((p = _mbsrchr (modname, '\\'))
2661 /* From bin means installed Emacs, from src means uninstalled. */
2662 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2664 char buf[SET_ENV_BUF_SIZE];
2665 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2667 *p = 0;
2668 for (p = modname; *p; p = CharNext (p))
2669 if (*p == '\\') *p = '/';
2671 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2672 _putenv (strdup (buf));
2673 /* If we are running from the Posix-like build tree, define
2674 SHELL to point to our own cmdproxy. The loop below will
2675 then disregard PATH_EXEC and the default value. */
2676 if (within_build_tree)
2678 _snprintf (buf, sizeof (buf) - 1,
2679 "SHELL=%s/nt/cmdproxy.exe", modname);
2680 _putenv (strdup (buf));
2685 for (i = 0; i < N_ENV_VARS; i++)
2687 if (!getenv (env_vars[i].name))
2689 int dont_free = 0;
2690 char bufc[SET_ENV_BUF_SIZE];
2692 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2693 /* Also ignore empty environment variables. */
2694 || *lpval == 0)
2696 xfree (lpval);
2697 dont_free = 1;
2698 if (strcmp (env_vars[i].name, "SHELL") == 0)
2700 /* Look for cmdproxy.exe in every directory in
2701 PATH_EXEC. FIXME: This does not find cmdproxy
2702 in nt/ when we run uninstalled. */
2703 char fname[MAX_PATH];
2704 const char *pstart = PATH_EXEC, *pend;
2706 do {
2707 pend = _mbschr (pstart, ';');
2708 if (!pend)
2709 pend = pstart + strlen (pstart);
2710 /* Be defensive against series of ;;; characters. */
2711 if (pend > pstart)
2713 strncpy (fname, pstart, pend - pstart);
2714 fname[pend - pstart] = '/';
2715 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2716 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2717 sizeof (bufc));
2718 if (sys_access (bufc, F_OK) == 0)
2720 lpval = bufc;
2721 dwType = REG_SZ;
2722 break;
2725 if (*pend)
2726 pstart = pend + 1;
2727 else
2728 pstart = pend;
2729 if (!*pstart)
2731 /* If not found in any directory, use the
2732 default as the last resort. */
2733 lpval = env_vars[i].def_value;
2734 dwType = REG_EXPAND_SZ;
2736 } while (*pstart);
2738 else
2740 lpval = env_vars[i].def_value;
2741 dwType = REG_EXPAND_SZ;
2743 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2744 Vdelayed_warnings_list
2745 = Fcons (listn (CONSTYPE_HEAP, 2,
2746 intern ("initialization"),
2747 build_string ("Setting HOME to C:\\ by default is deprecated")),
2748 Vdelayed_warnings_list);
2751 if (lpval)
2753 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2755 if (dwType == REG_EXPAND_SZ)
2756 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2757 else if (dwType == REG_SZ)
2758 strcpy (buf1, lpval);
2759 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2761 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2762 buf1);
2763 _putenv (strdup (buf2));
2766 if (!dont_free)
2767 xfree (lpval);
2773 /* Rebuild system configuration to reflect invoking system. */
2774 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2776 /* Another special case: on NT, the PATH variable is actually named
2777 "Path" although cmd.exe (perhaps NT itself) arranges for
2778 environment variable lookup and setting to be case insensitive.
2779 However, Emacs assumes a fully case sensitive environment, so we
2780 need to change "Path" to "PATH" to match the expectations of
2781 various elisp packages. We do this by the sneaky method of
2782 modifying the string in the C runtime environ entry.
2784 The same applies to COMSPEC. */
2786 char ** envp;
2788 for (envp = environ; *envp; envp++)
2789 if (_strnicmp (*envp, "PATH=", 5) == 0)
2790 memcpy (*envp, "PATH=", 5);
2791 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2792 memcpy (*envp, "COMSPEC=", 8);
2795 /* Remember the initial working directory for getcwd. */
2796 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2797 Does it matter anywhere in Emacs? */
2798 if (w32_unicode_filenames)
2800 wchar_t wstartup_dir[MAX_PATH];
2802 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2803 emacs_abort ();
2804 filename_from_utf16 (wstartup_dir, startup_dir);
2806 else
2808 char astartup_dir[MAX_PATH];
2810 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2811 emacs_abort ();
2812 filename_from_ansi (astartup_dir, startup_dir);
2816 static char modname[MAX_PATH];
2818 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2819 emacs_abort ();
2820 argv[0] = modname;
2823 /* Determine if there is a middle mouse button, to allow parse_button
2824 to decide whether right mouse events should be mouse-2 or
2825 mouse-3. */
2826 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2828 init_user_info ();
2831 /* Called from expand-file-name when default-directory is not a string. */
2833 char *
2834 emacs_root_dir (void)
2836 static char root_dir[MAX_UTF8_PATH];
2837 const char *p;
2839 p = getenv ("emacs_dir");
2840 if (p == NULL)
2841 emacs_abort ();
2842 filename_from_ansi (p, root_dir);
2843 root_dir[parse_root (root_dir, NULL)] = '\0';
2844 dostounix_filename (root_dir);
2845 return root_dir;
2848 #include <sys/timeb.h>
2850 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2852 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2854 struct _timeb tb;
2855 _ftime (&tb);
2857 tv->tv_sec = tb.time;
2858 tv->tv_usec = tb.millitm * 1000L;
2859 /* Implementation note: _ftime sometimes doesn't update the dstflag
2860 according to the new timezone when the system timezone is
2861 changed. We could fix that by using GetSystemTime and
2862 GetTimeZoneInformation, but that doesn't seem necessary, since
2863 Emacs always calls gettimeofday with the 2nd argument NULL (see
2864 current_emacs_time). */
2865 if (tz)
2867 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2868 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2870 return 0;
2873 /* Emulate fdutimens. */
2875 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2876 TIMESPEC[0] and TIMESPEC[1], respectively.
2877 FD must be either negative -- in which case it is ignored --
2878 or a file descriptor that is open on FILE.
2879 If FD is nonnegative, then FILE can be NULL, which means
2880 use just futimes instead of utimes.
2881 If TIMESPEC is null, FAIL.
2882 Return 0 on success, -1 (setting errno) on failure. */
2885 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2887 if (!timespec)
2889 errno = ENOSYS;
2890 return -1;
2892 if (fd < 0 && !file)
2894 errno = EBADF;
2895 return -1;
2897 /* _futime's prototype defines 2nd arg as having the type 'struct
2898 _utimbuf', while utime needs to accept 'struct utimbuf' for
2899 compatibility with Posix. So we need to use 2 different (but
2900 equivalent) types to avoid compiler warnings, sigh. */
2901 if (fd >= 0)
2903 struct _utimbuf _ut;
2905 _ut.actime = timespec[0].tv_sec;
2906 _ut.modtime = timespec[1].tv_sec;
2907 return _futime (fd, &_ut);
2909 else
2911 struct utimbuf ut;
2913 ut.actime = timespec[0].tv_sec;
2914 ut.modtime = timespec[1].tv_sec;
2915 /* Call 'utime', which is implemented below, not the MS library
2916 function, which fails on directories. */
2917 return utime (file, &ut);
2922 /* ------------------------------------------------------------------------- */
2923 /* IO support and wrapper functions for the Windows API. */
2924 /* ------------------------------------------------------------------------- */
2926 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2927 on network directories, so we handle that case here.
2928 (Ulrich Leodolter, 1/11/95). */
2929 char *
2930 sys_ctime (const time_t *t)
2932 char *str = (char *) ctime (t);
2933 return (str ? str : "Sun Jan 01 00:00:00 1970");
2936 /* Emulate sleep...we could have done this with a define, but that
2937 would necessitate including windows.h in the files that used it.
2938 This is much easier. */
2939 void
2940 sys_sleep (int seconds)
2942 Sleep (seconds * 1000);
2945 /* Internal MSVC functions for low-level descriptor munging */
2946 extern int __cdecl _set_osfhnd (int fd, long h);
2947 extern int __cdecl _free_osfhnd (int fd);
2949 /* parallel array of private info on file handles */
2950 filedesc fd_info [ MAXDESC ];
2952 typedef struct volume_info_data {
2953 struct volume_info_data * next;
2955 /* time when info was obtained */
2956 DWORD timestamp;
2958 /* actual volume info */
2959 char * root_dir;
2960 DWORD serialnum;
2961 DWORD maxcomp;
2962 DWORD flags;
2963 char * name;
2964 char * type;
2965 } volume_info_data;
2967 /* Global referenced by various functions. */
2968 static volume_info_data volume_info;
2970 /* Vector to indicate which drives are local and fixed (for which cached
2971 data never expires). */
2972 static BOOL fixed_drives[26];
2974 /* Consider cached volume information to be stale if older than 10s,
2975 at least for non-local drives. Info for fixed drives is never stale. */
2976 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2977 #define VOLINFO_STILL_VALID( root_dir, info ) \
2978 ( ( isalpha (root_dir[0]) && \
2979 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2980 || GetTickCount () - info->timestamp < 10000 )
2982 /* Cache support functions. */
2984 /* Simple linked list with linear search is sufficient. */
2985 static volume_info_data *volume_cache = NULL;
2987 static volume_info_data *
2988 lookup_volume_info (char * root_dir)
2990 volume_info_data * info;
2992 for (info = volume_cache; info; info = info->next)
2993 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2994 break;
2995 return info;
2998 static void
2999 add_volume_info (char * root_dir, volume_info_data * info)
3001 info->root_dir = xstrdup (root_dir);
3002 unixtodos_filename (info->root_dir);
3003 info->next = volume_cache;
3004 volume_cache = info;
3008 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3009 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3010 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3011 static volume_info_data *
3012 GetCachedVolumeInformation (char * root_dir)
3014 volume_info_data * info;
3015 char default_root[ MAX_UTF8_PATH ];
3016 char name[MAX_PATH+1];
3017 char type[MAX_PATH+1];
3019 /* NULL for root_dir means use root from current directory. */
3020 if (root_dir == NULL)
3022 if (w32_unicode_filenames)
3024 wchar_t curdirw[MAX_PATH];
3026 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3027 return NULL;
3028 filename_from_utf16 (curdirw, default_root);
3030 else
3032 char curdira[MAX_PATH];
3034 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3035 return NULL;
3036 filename_from_ansi (curdira, default_root);
3038 parse_root (default_root, (const char **)&root_dir);
3039 *root_dir = 0;
3040 root_dir = default_root;
3043 /* Local fixed drives can be cached permanently. Removable drives
3044 cannot be cached permanently, since the volume name and serial
3045 number (if nothing else) can change. Remote drives should be
3046 treated as if they are removable, since there is no sure way to
3047 tell whether they are or not. Also, the UNC association of drive
3048 letters mapped to remote volumes can be changed at any time (even
3049 by other processes) without notice.
3051 As a compromise, so we can benefit from caching info for remote
3052 volumes, we use a simple expiry mechanism to invalidate cache
3053 entries that are more than ten seconds old. */
3055 #if 0
3056 /* No point doing this, because WNetGetConnection is even slower than
3057 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3058 GetDriveType is about the only call of this type which does not
3059 involve network access, and so is extremely quick). */
3061 /* Map drive letter to UNC if remote. */
3062 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3064 char remote_name[ 256 ];
3065 char drive[3] = { root_dir[0], ':' };
3067 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3068 == NO_ERROR)
3069 /* do something */ ;
3071 #endif
3073 info = lookup_volume_info (root_dir);
3075 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3077 DWORD serialnum;
3078 DWORD maxcomp;
3079 DWORD flags;
3081 /* Info is not cached, or is stale. */
3082 if (w32_unicode_filenames)
3084 wchar_t root_w[MAX_PATH];
3085 wchar_t name_w[MAX_PATH+1];
3086 wchar_t type_w[MAX_PATH+1];
3088 filename_to_utf16 (root_dir, root_w);
3089 if (!GetVolumeInformationW (root_w,
3090 name_w, sizeof (name_w),
3091 &serialnum,
3092 &maxcomp,
3093 &flags,
3094 type_w, sizeof (type_w)))
3095 return NULL;
3096 /* Hmm... not really 100% correct, as these 2 are not file
3097 names... */
3098 filename_from_utf16 (name_w, name);
3099 filename_from_utf16 (type_w, type);
3101 else
3103 char root_a[MAX_PATH];
3104 char name_a[MAX_PATH+1];
3105 char type_a[MAX_PATH+1];
3107 filename_to_ansi (root_dir, root_a);
3108 if (!GetVolumeInformationA (root_a,
3109 name_a, sizeof (name_a),
3110 &serialnum,
3111 &maxcomp,
3112 &flags,
3113 type_a, sizeof (type_a)))
3114 return NULL;
3115 filename_from_ansi (name_a, name);
3116 filename_from_ansi (type_a, type);
3119 /* Cache the volume information for future use, overwriting existing
3120 entry if present. */
3121 if (info == NULL)
3123 info = xmalloc (sizeof (volume_info_data));
3124 add_volume_info (root_dir, info);
3126 else
3128 xfree (info->name);
3129 xfree (info->type);
3132 info->name = xstrdup (name);
3133 unixtodos_filename (info->name);
3134 info->serialnum = serialnum;
3135 info->maxcomp = maxcomp;
3136 info->flags = flags;
3137 info->type = xstrdup (type);
3138 info->timestamp = GetTickCount ();
3141 return info;
3144 /* Get information on the volume where NAME is held; set path pointer to
3145 start of pathname in NAME (past UNC header\volume header if present),
3146 if pPath is non-NULL.
3148 Note: if NAME includes symlinks, the information is for the volume
3149 of the symlink, not of its target. That's because, even though
3150 GetVolumeInformation returns information about the symlink target
3151 of its argument, we only pass the root directory to
3152 GetVolumeInformation, not the full NAME. */
3153 static int
3154 get_volume_info (const char * name, const char ** pPath)
3156 char temp[MAX_UTF8_PATH];
3157 char *rootname = NULL; /* default to current volume */
3158 volume_info_data * info;
3159 int root_len = parse_root (name, pPath);
3161 if (name == NULL)
3162 return FALSE;
3164 /* Copy the root name of the volume, if given. */
3165 if (root_len)
3167 strncpy (temp, name, root_len);
3168 temp[root_len] = '\0';
3169 unixtodos_filename (temp);
3170 rootname = temp;
3173 info = GetCachedVolumeInformation (rootname);
3174 if (info != NULL)
3176 /* Set global referenced by other functions. */
3177 volume_info = *info;
3178 return TRUE;
3180 return FALSE;
3183 /* Determine if volume is FAT format (ie. only supports short 8.3
3184 names); also set path pointer to start of pathname in name, if
3185 pPath is non-NULL. */
3186 static int
3187 is_fat_volume (const char * name, const char ** pPath)
3189 if (get_volume_info (name, pPath))
3190 return (volume_info.maxcomp == 12);
3191 return FALSE;
3194 /* Convert all slashes in a filename to backslashes, and map filename
3195 to a valid 8.3 name if necessary. The result is a pointer to a
3196 static buffer, so CAVEAT EMPTOR! */
3197 const char *
3198 map_w32_filename (const char * name, const char ** pPath)
3200 static char shortname[MAX_UTF8_PATH];
3201 char * str = shortname;
3202 char c;
3203 char * path;
3204 const char * save_name = name;
3206 if (strlen (name) >= sizeof (shortname))
3208 /* Return a filename which will cause callers to fail. */
3209 strcpy (shortname, "?");
3210 return shortname;
3213 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3215 register int left = 8; /* maximum number of chars in part */
3216 register int extn = 0; /* extension added? */
3217 register int dots = 2; /* maximum number of dots allowed */
3219 while (name < path)
3220 *str++ = *name++; /* skip past UNC header */
3222 while ((c = *name++))
3224 switch ( c )
3226 case ':':
3227 case '\\':
3228 case '/':
3229 *str++ = (c == ':' ? ':' : '\\');
3230 extn = 0; /* reset extension flags */
3231 dots = 2; /* max 2 dots */
3232 left = 8; /* max length 8 for main part */
3233 break;
3234 case '.':
3235 if ( dots )
3237 /* Convert path components of the form .xxx to _xxx,
3238 but leave . and .. as they are. This allows .emacs
3239 to be read as _emacs, for example. */
3241 if (! *name ||
3242 *name == '.' ||
3243 IS_DIRECTORY_SEP (*name))
3245 *str++ = '.';
3246 dots--;
3248 else
3250 *str++ = '_';
3251 left--;
3252 dots = 0;
3255 else if ( !extn )
3257 *str++ = '.';
3258 extn = 1; /* we've got an extension */
3259 left = 3; /* 3 chars in extension */
3261 else
3263 /* any embedded dots after the first are converted to _ */
3264 *str++ = '_';
3266 break;
3267 case '~':
3268 case '#': /* don't lose these, they're important */
3269 if ( ! left )
3270 str[-1] = c; /* replace last character of part */
3271 /* FALLTHRU */
3272 default:
3273 if ( left && 'A' <= c && c <= 'Z' )
3275 *str++ = tolower (c); /* map to lower case (looks nicer) */
3276 left--;
3277 dots = 0; /* started a path component */
3279 break;
3282 *str = '\0';
3284 else
3286 strcpy (shortname, name);
3287 unixtodos_filename (shortname);
3290 if (pPath)
3291 *pPath = shortname + (path - save_name);
3293 return shortname;
3296 static int
3297 is_exec (const char * name)
3299 char * p = strrchr (name, '.');
3300 return
3301 (p != NULL
3302 && (xstrcasecmp (p, ".exe") == 0 ||
3303 xstrcasecmp (p, ".com") == 0 ||
3304 xstrcasecmp (p, ".bat") == 0 ||
3305 xstrcasecmp (p, ".cmd") == 0));
3308 /* Emulate the Unix directory procedures opendir, closedir, and
3309 readdir. We rename them to sys_* names because some versions of
3310 MinGW startup code call opendir and readdir to glob wildcards, and
3311 the code that calls them doesn't grok UTF-8 encoded file names we
3312 produce in dirent->d_name[]. */
3314 struct dirent dir_static; /* simulated directory contents */
3315 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3316 static int dir_is_fat;
3317 static char dir_pathname[MAX_UTF8_PATH];
3318 static WIN32_FIND_DATAW dir_find_data_w;
3319 static WIN32_FIND_DATAA dir_find_data_a;
3320 #define DIR_FIND_DATA_W 1
3321 #define DIR_FIND_DATA_A 2
3322 static int last_dir_find_data = -1;
3324 /* Support shares on a network resource as subdirectories of a read-only
3325 root directory. */
3326 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3327 static HANDLE open_unc_volume (const char *);
3328 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3329 static void close_unc_volume (HANDLE);
3331 DIR *
3332 sys_opendir (const char *filename)
3334 DIR *dirp;
3336 /* Opening is done by FindFirstFile. However, a read is inherent to
3337 this operation, so we defer the open until read time. */
3339 if (dir_find_handle != INVALID_HANDLE_VALUE)
3340 return NULL;
3341 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3342 return NULL;
3344 /* Note: We don't support traversal of UNC volumes via symlinks.
3345 Doing so would mean punishing 99.99% of use cases by resolving
3346 all the possible symlinks in FILENAME, recursively. */
3347 if (is_unc_volume (filename))
3349 wnet_enum_handle = open_unc_volume (filename);
3350 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3351 return NULL;
3354 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3355 return NULL;
3357 dirp->dd_fd = 0;
3358 dirp->dd_loc = 0;
3359 dirp->dd_size = 0;
3361 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3362 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3363 /* Note: We don't support symlinks to file names on FAT volumes.
3364 Doing so would mean punishing 99.99% of use cases by resolving
3365 all the possible symlinks in FILENAME, recursively. */
3366 dir_is_fat = is_fat_volume (filename, NULL);
3368 return dirp;
3371 void
3372 sys_closedir (DIR *dirp)
3374 /* If we have a find-handle open, close it. */
3375 if (dir_find_handle != INVALID_HANDLE_VALUE)
3377 FindClose (dir_find_handle);
3378 dir_find_handle = INVALID_HANDLE_VALUE;
3380 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3382 close_unc_volume (wnet_enum_handle);
3383 wnet_enum_handle = INVALID_HANDLE_VALUE;
3385 xfree ((char *) dirp);
3388 struct dirent *
3389 sys_readdir (DIR *dirp)
3391 int downcase = !NILP (Vw32_downcase_file_names);
3393 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3395 if (!read_unc_volume (wnet_enum_handle,
3396 dir_find_data_w.cFileName,
3397 dir_find_data_a.cFileName,
3398 MAX_PATH))
3399 return NULL;
3401 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3402 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3404 char filename[MAX_UTF8_PATH];
3405 int ln;
3406 bool last_slash = true;
3408 /* Note: We don't need to worry about dir_pathname being longer
3409 than MAX_UTF8_PATH, as sys_opendir already took care of that
3410 when it called map_w32_filename: that function will put a "?"
3411 in its return value in that case, thus failing all the calls
3412 below. */
3413 strcpy (filename, dir_pathname);
3414 ln = strlen (filename);
3415 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3416 last_slash = false;
3418 /* Note: No need to resolve symlinks in FILENAME, because
3419 FindFirst opens the directory that is the target of a
3420 symlink. */
3421 if (w32_unicode_filenames)
3423 wchar_t fnw[MAX_PATH + 2];
3425 filename_to_utf16 (filename, fnw);
3426 if (!last_slash)
3427 wcscat (fnw, L"\\");
3428 wcscat (fnw, L"*");
3429 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3431 else
3433 char fna[MAX_PATH + 2];
3435 filename_to_ansi (filename, fna);
3436 if (!last_slash)
3437 strcat (fna, "\\");
3438 strcat (fna, "*");
3439 /* If FILENAME is not representable by the current ANSI
3440 codepage, we don't want FindFirstFileA to interpret the
3441 '?' characters as a wildcard. */
3442 if (_mbspbrk (fna, "?"))
3443 dir_find_handle = INVALID_HANDLE_VALUE;
3444 else
3445 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3448 if (dir_find_handle == INVALID_HANDLE_VALUE)
3450 /* Any changes in the value of errno here should be in sync
3451 with what directory_files_internal does when it calls
3452 readdir. */
3453 switch (GetLastError ())
3455 /* Windows uses this value when FindFirstFile finds no
3456 files that match the wildcard. This is not supposed
3457 to happen, since our wildcard is "*", but just in
3458 case, if there's some weird empty directory with not
3459 even "." and ".." entries... */
3460 case ERROR_FILE_NOT_FOUND:
3461 errno = 0;
3462 /* FALLTHRU */
3463 default:
3464 break;
3465 case ERROR_ACCESS_DENIED:
3466 case ERROR_NETWORK_ACCESS_DENIED:
3467 errno = EACCES;
3468 break;
3469 case ERROR_PATH_NOT_FOUND:
3470 case ERROR_INVALID_DRIVE:
3471 case ERROR_NOT_READY:
3472 case ERROR_BAD_NETPATH:
3473 case ERROR_BAD_NET_NAME:
3474 errno = ENOENT;
3475 break;
3477 return NULL;
3480 else if (w32_unicode_filenames)
3482 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3484 errno = 0;
3485 return NULL;
3488 else
3490 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3492 errno = 0;
3493 return NULL;
3497 /* Emacs never uses this value, so don't bother making it match
3498 value returned by stat(). */
3499 dir_static.d_ino = 1;
3501 if (w32_unicode_filenames)
3503 if (downcase || dir_is_fat)
3505 wchar_t tem[MAX_PATH];
3507 wcscpy (tem, dir_find_data_w.cFileName);
3508 CharLowerW (tem);
3509 filename_from_utf16 (tem, dir_static.d_name);
3511 else
3512 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3513 last_dir_find_data = DIR_FIND_DATA_W;
3515 else
3517 char tem[MAX_PATH];
3519 /* If the file name in cFileName[] includes `?' characters, it
3520 means the original file name used characters that cannot be
3521 represented by the current ANSI codepage. To avoid total
3522 lossage, retrieve the short 8+3 alias of the long file
3523 name. */
3524 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3526 strcpy (tem, dir_find_data_a.cAlternateFileName);
3527 /* 8+3 aliases are returned in all caps, which could break
3528 various alists that look at filenames' extensions. */
3529 downcase = 1;
3531 else if (downcase || dir_is_fat)
3532 strcpy (tem, dir_find_data_a.cFileName);
3533 else
3534 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3535 if (downcase || dir_is_fat)
3537 _mbslwr (tem);
3538 filename_from_ansi (tem, dir_static.d_name);
3540 last_dir_find_data = DIR_FIND_DATA_A;
3543 dir_static.d_namlen = strlen (dir_static.d_name);
3544 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3545 dir_static.d_namlen - dir_static.d_namlen % 4;
3547 return &dir_static;
3550 static HANDLE
3551 open_unc_volume (const char *path)
3553 const char *fn = map_w32_filename (path, NULL);
3554 DWORD result;
3555 HANDLE henum;
3557 if (w32_unicode_filenames)
3559 NETRESOURCEW nrw;
3560 wchar_t fnw[MAX_PATH];
3562 nrw.dwScope = RESOURCE_GLOBALNET;
3563 nrw.dwType = RESOURCETYPE_DISK;
3564 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3565 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3566 nrw.lpLocalName = NULL;
3567 filename_to_utf16 (fn, fnw);
3568 nrw.lpRemoteName = fnw;
3569 nrw.lpComment = NULL;
3570 nrw.lpProvider = NULL;
3572 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3573 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3575 else
3577 NETRESOURCEA nra;
3578 char fna[MAX_PATH];
3580 nra.dwScope = RESOURCE_GLOBALNET;
3581 nra.dwType = RESOURCETYPE_DISK;
3582 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3583 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3584 nra.lpLocalName = NULL;
3585 filename_to_ansi (fn, fna);
3586 nra.lpRemoteName = fna;
3587 nra.lpComment = NULL;
3588 nra.lpProvider = NULL;
3590 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3591 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3593 if (result == NO_ERROR)
3594 return henum;
3595 else
3597 /* Make sure directory_files_internal reports a sensible error. */
3598 errno = ENOENT;
3599 return INVALID_HANDLE_VALUE;
3603 static void *
3604 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3606 DWORD count;
3607 int result;
3608 char *buffer;
3609 DWORD bufsize = 512;
3610 void *retval;
3612 count = 1;
3613 if (w32_unicode_filenames)
3615 wchar_t *ptrw;
3617 bufsize *= 2;
3618 buffer = alloca (bufsize);
3619 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3620 if (result != NO_ERROR)
3621 return NULL;
3622 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3623 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3624 ptrw += 2;
3625 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3626 ptrw++;
3627 wcsncpy (fname_w, ptrw, size);
3628 retval = fname_w;
3630 else
3632 int dbcs_p = max_filename_mbslen () > 1;
3633 char *ptra;
3635 buffer = alloca (bufsize);
3636 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3637 if (result != NO_ERROR)
3638 return NULL;
3639 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3640 ptra += 2;
3641 if (!dbcs_p)
3642 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3643 else
3645 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3646 ptra = CharNextExA (file_name_codepage, ptra, 0);
3648 ptra++;
3649 strncpy (fname_a, ptra, size);
3650 retval = fname_a;
3653 return retval;
3656 static void
3657 close_unc_volume (HANDLE henum)
3659 if (henum != INVALID_HANDLE_VALUE)
3660 WNetCloseEnum (henum);
3663 static DWORD
3664 unc_volume_file_attributes (const char *path)
3666 HANDLE henum;
3667 DWORD attrs;
3669 henum = open_unc_volume (path);
3670 if (henum == INVALID_HANDLE_VALUE)
3671 return -1;
3673 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3675 close_unc_volume (henum);
3677 return attrs;
3680 /* Ensure a network connection is authenticated. */
3681 static void
3682 logon_network_drive (const char *path)
3684 char share[MAX_UTF8_PATH];
3685 int n_slashes;
3686 char drive[4];
3687 UINT drvtype;
3688 char *p;
3689 DWORD val;
3691 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3692 drvtype = DRIVE_REMOTE;
3693 else if (path[0] == '\0' || path[1] != ':')
3694 drvtype = GetDriveType (NULL);
3695 else
3697 drive[0] = path[0];
3698 drive[1] = ':';
3699 drive[2] = '\\';
3700 drive[3] = '\0';
3701 drvtype = GetDriveType (drive);
3704 /* Only logon to networked drives. */
3705 if (drvtype != DRIVE_REMOTE)
3706 return;
3708 n_slashes = 2;
3709 strncpy (share, path, MAX_UTF8_PATH);
3710 /* Truncate to just server and share name. */
3711 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3713 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3715 *p = '\0';
3716 break;
3720 if (w32_unicode_filenames)
3722 NETRESOURCEW resourcew;
3723 wchar_t share_w[MAX_PATH];
3725 resourcew.dwScope = RESOURCE_GLOBALNET;
3726 resourcew.dwType = RESOURCETYPE_DISK;
3727 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3728 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3729 resourcew.lpLocalName = NULL;
3730 filename_to_utf16 (share, share_w);
3731 resourcew.lpRemoteName = share_w;
3732 resourcew.lpProvider = NULL;
3734 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3736 else
3738 NETRESOURCEA resourcea;
3739 char share_a[MAX_PATH];
3741 resourcea.dwScope = RESOURCE_GLOBALNET;
3742 resourcea.dwType = RESOURCETYPE_DISK;
3743 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3744 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3745 resourcea.lpLocalName = NULL;
3746 filename_to_ansi (share, share_a);
3747 resourcea.lpRemoteName = share_a;
3748 resourcea.lpProvider = NULL;
3750 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3753 switch (val)
3755 case NO_ERROR:
3756 case ERROR_ALREADY_ASSIGNED:
3757 break;
3758 case ERROR_ACCESS_DENIED:
3759 case ERROR_LOGON_FAILURE:
3760 errno = EACCES;
3761 break;
3762 case ERROR_BUSY:
3763 errno = EAGAIN;
3764 break;
3765 case ERROR_BAD_NET_NAME:
3766 case ERROR_NO_NET_OR_BAD_PATH:
3767 case ERROR_NO_NETWORK:
3768 case ERROR_CANCELLED:
3769 default:
3770 errno = ENOENT;
3771 break;
3775 /* Emulate faccessat(2). */
3777 faccessat (int dirfd, const char * path, int mode, int flags)
3779 DWORD attributes;
3781 if (dirfd != AT_FDCWD
3782 && !(IS_DIRECTORY_SEP (path[0])
3783 || IS_DEVICE_SEP (path[1])))
3785 errno = EBADF;
3786 return -1;
3789 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3790 newer versions blow up when passed D_OK. */
3791 path = map_w32_filename (path, NULL);
3792 /* If the last element of PATH is a symlink, we need to resolve it
3793 to get the attributes of its target file. Note: any symlinks in
3794 PATH elements other than the last one are transparently resolved
3795 by GetFileAttributes below. */
3796 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3797 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3798 path = chase_symlinks (path);
3800 if (w32_unicode_filenames)
3802 wchar_t path_w[MAX_PATH];
3804 filename_to_utf16 (path, path_w);
3805 attributes = GetFileAttributesW (path_w);
3807 else
3809 char path_a[MAX_PATH];
3811 filename_to_ansi (path, path_a);
3812 attributes = GetFileAttributesA (path_a);
3815 if (attributes == -1)
3817 DWORD w32err = GetLastError ();
3819 switch (w32err)
3821 case ERROR_INVALID_NAME:
3822 case ERROR_BAD_PATHNAME:
3823 if (is_unc_volume (path))
3825 attributes = unc_volume_file_attributes (path);
3826 if (attributes == -1)
3828 errno = EACCES;
3829 return -1;
3831 goto check_attrs;
3833 /* FALLTHROUGH */
3834 case ERROR_FILE_NOT_FOUND:
3835 case ERROR_BAD_NETPATH:
3836 errno = ENOENT;
3837 break;
3838 default:
3839 errno = EACCES;
3840 break;
3842 return -1;
3845 check_attrs:
3846 if ((mode & X_OK) != 0
3847 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3849 errno = EACCES;
3850 return -1;
3852 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3854 errno = EACCES;
3855 return -1;
3857 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3859 errno = EACCES;
3860 return -1;
3862 return 0;
3865 /* A special test for DIRNAME being a directory accessible by the
3866 current user. This is needed because the security permissions in
3867 directory's ACLs are not visible in the Posix-style mode bits
3868 returned by 'stat' and in attributes returned by GetFileAttributes.
3869 So a directory would seem like it's readable by the current user,
3870 but will in fact error out with EACCES when they actually try. */
3872 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3874 char pattern[MAX_UTF8_PATH];
3875 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
3876 HANDLE dh;
3878 /* Network volumes need a different reading method. */
3879 if (is_unc_volume (dirname))
3881 void *read_result = NULL;
3882 wchar_t fnw[MAX_PATH];
3883 char fna[MAX_PATH];
3885 dh = open_unc_volume (dirname);
3886 if (dh != INVALID_HANDLE_VALUE)
3888 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
3889 close_unc_volume (dh);
3891 /* Treat empty volumes as accessible. */
3892 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
3895 /* Note: map_w32_filename makes sure DIRNAME is not longer than
3896 MAX_UTF8_PATH. */
3897 strcpy (pattern, map_w32_filename (dirname, NULL));
3899 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
3900 opens the directory that is the target of a symlink. */
3901 if (w32_unicode_filenames)
3903 wchar_t pat_w[MAX_PATH + 2];
3904 WIN32_FIND_DATAW dfd_w;
3906 filename_to_utf16 (pattern, pat_w);
3907 if (!last_slash)
3908 wcscat (pat_w, L"\\");
3909 wcscat (pat_w, L"*");
3910 dh = FindFirstFileW (pat_w, &dfd_w);
3912 else
3914 char pat_a[MAX_PATH + 2];
3915 WIN32_FIND_DATAA dfd_a;
3917 filename_to_ansi (pattern, pat_a);
3918 if (!last_slash)
3919 strcpy (pat_a, "\\");
3920 strcat (pat_a, "*");
3921 /* In case DIRNAME cannot be expressed in characters from the
3922 current ANSI codepage. */
3923 if (_mbspbrk (pat_a, "?"))
3924 dh = INVALID_HANDLE_VALUE;
3925 else
3926 dh = FindFirstFileA (pat_a, &dfd_a);
3929 if (dh == INVALID_HANDLE_VALUE)
3930 return 0;
3931 FindClose (dh);
3932 return 1;
3935 /* A version of 'access' to be used locally with file names in
3936 locale-specific encoding. Does not resolve symlinks and does not
3937 support file names on FAT12 and FAT16 volumes, but that's OK, since
3938 we only invoke this function for files inside the Emacs source or
3939 installation tree, on directories (so any symlinks should have the
3940 directory bit set), and on short file names such as "C:/.emacs". */
3941 static int
3942 sys_access (const char *fname, int mode)
3944 char fname_copy[MAX_PATH], *p;
3945 DWORD attributes;
3947 strcpy (fname_copy, fname);
3948 /* Do the equivalent of unixtodos_filename. */
3949 for (p = fname_copy; *p; p = CharNext (p))
3950 if (*p == '/')
3951 *p = '\\';
3953 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3955 DWORD w32err = GetLastError ();
3957 switch (w32err)
3959 case ERROR_INVALID_NAME:
3960 case ERROR_BAD_PATHNAME:
3961 case ERROR_FILE_NOT_FOUND:
3962 case ERROR_BAD_NETPATH:
3963 errno = ENOENT;
3964 break;
3965 default:
3966 errno = EACCES;
3967 break;
3969 return -1;
3971 if ((mode & X_OK) != 0
3972 && !(is_exec (fname_copy)
3973 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3975 errno = EACCES;
3976 return -1;
3978 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3980 errno = EACCES;
3981 return -1;
3983 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3985 errno = EACCES;
3986 return -1;
3988 return 0;
3991 /* Shadow some MSVC runtime functions to map requests for long filenames
3992 to reasonable short names if necessary. This was originally added to
3993 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3994 long file names. */
3997 sys_chdir (const char * path)
3999 path = map_w32_filename (path, NULL);
4000 if (w32_unicode_filenames)
4002 wchar_t newdir_w[MAX_PATH];
4004 if (filename_to_utf16 (path, newdir_w) == 0)
4005 return _wchdir (newdir_w);
4006 return -1;
4008 else
4010 char newdir_a[MAX_PATH];
4012 if (filename_to_ansi (path, newdir_a) == 0)
4013 return _chdir (newdir_a);
4014 return -1;
4019 sys_chmod (const char * path, int mode)
4021 path = chase_symlinks (map_w32_filename (path, NULL));
4022 if (w32_unicode_filenames)
4024 wchar_t path_w[MAX_PATH];
4026 filename_to_utf16 (path, path_w);
4027 return _wchmod (path_w, mode);
4029 else
4031 char path_a[MAX_PATH];
4033 filename_to_ansi (path, path_a);
4034 return _chmod (path_a, mode);
4039 sys_creat (const char * path, int mode)
4041 path = map_w32_filename (path, NULL);
4042 if (w32_unicode_filenames)
4044 wchar_t path_w[MAX_PATH];
4046 filename_to_utf16 (path, path_w);
4047 return _wcreat (path_w, mode);
4049 else
4051 char path_a[MAX_PATH];
4053 filename_to_ansi (path, path_a);
4054 return _creat (path_a, mode);
4058 FILE *
4059 sys_fopen (const char * path, const char * mode)
4061 int fd;
4062 int oflag;
4063 const char * mode_save = mode;
4065 /* Force all file handles to be non-inheritable. This is necessary to
4066 ensure child processes don't unwittingly inherit handles that might
4067 prevent future file access. */
4069 if (mode[0] == 'r')
4070 oflag = O_RDONLY;
4071 else if (mode[0] == 'w' || mode[0] == 'a')
4072 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4073 else
4074 return NULL;
4076 /* Only do simplistic option parsing. */
4077 while (*++mode)
4078 if (mode[0] == '+')
4080 oflag &= ~(O_RDONLY | O_WRONLY);
4081 oflag |= O_RDWR;
4083 else if (mode[0] == 'b')
4085 oflag &= ~O_TEXT;
4086 oflag |= O_BINARY;
4088 else if (mode[0] == 't')
4090 oflag &= ~O_BINARY;
4091 oflag |= O_TEXT;
4093 else break;
4095 path = map_w32_filename (path, NULL);
4096 if (w32_unicode_filenames)
4098 wchar_t path_w[MAX_PATH];
4100 filename_to_utf16 (path, path_w);
4101 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4103 else
4105 char path_a[MAX_PATH];
4107 filename_to_ansi (path, path_a);
4108 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4110 if (fd < 0)
4111 return NULL;
4113 return _fdopen (fd, mode_save);
4116 /* This only works on NTFS volumes, but is useful to have. */
4118 sys_link (const char * old, const char * new)
4120 HANDLE fileh;
4121 int result = -1;
4122 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4123 wchar_t oldname_w[MAX_PATH];
4124 char oldname_a[MAX_PATH];
4126 if (old == NULL || new == NULL)
4128 errno = ENOENT;
4129 return -1;
4132 strcpy (oldname, map_w32_filename (old, NULL));
4133 strcpy (newname, map_w32_filename (new, NULL));
4135 if (w32_unicode_filenames)
4137 filename_to_utf16 (oldname, oldname_w);
4138 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4139 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4141 else
4143 filename_to_ansi (oldname, oldname_a);
4144 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4145 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4147 if (fileh != INVALID_HANDLE_VALUE)
4149 int wlen;
4151 /* Confusingly, the "alternate" stream name field does not apply
4152 when restoring a hard link, and instead contains the actual
4153 stream data for the link (ie. the name of the link to create).
4154 The WIN32_STREAM_ID structure before the cStreamName field is
4155 the stream header, which is then immediately followed by the
4156 stream data. */
4158 struct {
4159 WIN32_STREAM_ID wid;
4160 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4161 } data;
4163 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4164 indicates that flag is unsupported for CP_UTF8, and OTOH says
4165 it is the default anyway. */
4166 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4167 data.wid.cStreamName, MAX_PATH);
4168 if (wlen > 0)
4170 LPVOID context = NULL;
4171 DWORD wbytes = 0;
4173 data.wid.dwStreamId = BACKUP_LINK;
4174 data.wid.dwStreamAttributes = 0;
4175 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4176 data.wid.Size.HighPart = 0;
4177 data.wid.dwStreamNameSize = 0;
4179 if (BackupWrite (fileh, (LPBYTE)&data,
4180 offsetof (WIN32_STREAM_ID, cStreamName)
4181 + data.wid.Size.LowPart,
4182 &wbytes, FALSE, FALSE, &context)
4183 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4185 /* succeeded */
4186 result = 0;
4188 else
4190 DWORD err = GetLastError ();
4191 DWORD attributes;
4193 switch (err)
4195 case ERROR_ACCESS_DENIED:
4196 /* This is what happens when OLDNAME is a directory,
4197 since Windows doesn't support hard links to
4198 directories. Posix says to set errno to EPERM in
4199 that case. */
4200 if (w32_unicode_filenames)
4201 attributes = GetFileAttributesW (oldname_w);
4202 else
4203 attributes = GetFileAttributesA (oldname_a);
4204 if (attributes != -1
4205 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4206 errno = EPERM;
4207 else if (attributes == -1
4208 && is_unc_volume (oldname)
4209 && unc_volume_file_attributes (oldname) != -1)
4210 errno = EPERM;
4211 else
4212 errno = EACCES;
4213 break;
4214 case ERROR_TOO_MANY_LINKS:
4215 errno = EMLINK;
4216 break;
4217 case ERROR_NOT_SAME_DEVICE:
4218 errno = EXDEV;
4219 break;
4220 default:
4221 errno = EINVAL;
4222 break;
4227 CloseHandle (fileh);
4229 else
4230 errno = ENOENT;
4232 return result;
4236 sys_mkdir (const char * path)
4238 path = map_w32_filename (path, NULL);
4240 if (w32_unicode_filenames)
4242 wchar_t path_w[MAX_PATH];
4244 filename_to_utf16 (path, path_w);
4245 return _wmkdir (path_w);
4247 else
4249 char path_a[MAX_PATH];
4251 filename_to_ansi (path, path_a);
4252 return _mkdir (path_a);
4257 sys_open (const char * path, int oflag, int mode)
4259 const char* mpath = map_w32_filename (path, NULL);
4260 int res = -1;
4262 if (w32_unicode_filenames)
4264 wchar_t mpath_w[MAX_PATH];
4266 filename_to_utf16 (mpath, mpath_w);
4267 /* If possible, try to open file without _O_CREAT, to be able to
4268 write to existing hidden and system files. Force all file
4269 handles to be non-inheritable. */
4270 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4271 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4272 if (res < 0)
4273 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4275 else
4277 char mpath_a[MAX_PATH];
4279 filename_to_ansi (mpath, mpath_a);
4280 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4281 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4282 if (res < 0)
4283 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4286 return res;
4289 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4290 when using mktemp.
4292 Standard algorithm for generating a temporary file name seems to be
4293 use pid or tid with a letter on the front (in place of the 6 X's)
4294 and cycle through the letters to find a unique name. We extend
4295 that to allow any reasonable character as the first of the 6 X's,
4296 so that the number of simultaneously used temporary files will be
4297 greater. */
4300 mkostemp (char * template, int flags)
4302 char * p;
4303 int i, fd = -1;
4304 unsigned uid = GetCurrentThreadId ();
4305 int save_errno = errno;
4306 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4308 errno = EINVAL;
4309 if (template == NULL)
4310 return -1;
4312 p = template + strlen (template);
4313 i = 5;
4314 /* replace up to the last 5 X's with uid in decimal */
4315 while (--p >= template && p[0] == 'X' && --i >= 0)
4317 p[0] = '0' + uid % 10;
4318 uid /= 10;
4321 if (i < 0 && p[0] == 'X')
4323 i = 0;
4326 p[0] = first_char[i];
4327 if ((fd = sys_open (template,
4328 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4329 S_IRUSR | S_IWUSR)) >= 0
4330 || errno != EEXIST)
4332 if (fd >= 0)
4333 errno = save_errno;
4334 return fd;
4337 while (++i < sizeof (first_char));
4340 /* Template is badly formed or else we can't generate a unique name. */
4341 return -1;
4345 fchmod (int fd, mode_t mode)
4347 return 0;
4351 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4353 BOOL result;
4354 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4355 int newname_dev;
4356 int oldname_dev;
4357 bool have_temp_a = false;
4359 /* MoveFile on Windows 95 doesn't correctly change the short file name
4360 alias in a number of circumstances (it is not easy to predict when
4361 just by looking at oldname and newname, unfortunately). In these
4362 cases, renaming through a temporary name avoids the problem.
4364 A second problem on Windows 95 is that renaming through a temp name when
4365 newname is uppercase fails (the final long name ends up in
4366 lowercase, although the short alias might be uppercase) UNLESS the
4367 long temp name is not 8.3.
4369 So, on Windows 95 we always rename through a temp name, and we make sure
4370 the temp name has a long extension to ensure correct renaming. */
4372 strcpy (temp, map_w32_filename (oldname, NULL));
4374 /* volume_info is set indirectly by map_w32_filename. */
4375 oldname_dev = volume_info.serialnum;
4377 if (os_subtype == OS_9X)
4379 char * o;
4380 char * p;
4381 int i = 0;
4382 char oldname_a[MAX_PATH];
4384 oldname = map_w32_filename (oldname, NULL);
4385 filename_to_ansi (oldname, oldname_a);
4386 filename_to_ansi (temp, temp_a);
4387 if ((o = strrchr (oldname_a, '\\')))
4388 o++;
4389 else
4390 o = (char *) oldname_a;
4392 if ((p = strrchr (temp_a, '\\')))
4393 p++;
4394 else
4395 p = temp_a;
4399 /* Force temp name to require a manufactured 8.3 alias - this
4400 seems to make the second rename work properly. */
4401 sprintf (p, "_.%s.%u", o, i);
4402 i++;
4403 result = rename (oldname_a, temp_a);
4405 /* This loop must surely terminate! */
4406 while (result < 0 && errno == EEXIST);
4407 if (result < 0)
4408 return -1;
4409 have_temp_a = true;
4412 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4413 (at least if it is a file; don't do this for directories).
4415 Since we mustn't do this if we are just changing the case of the
4416 file name (we would end up deleting the file we are trying to
4417 rename!), we let rename detect if the destination file already
4418 exists - that way we avoid the possible pitfalls of trying to
4419 determine ourselves whether two names really refer to the same
4420 file, which is not always possible in the general case. (Consider
4421 all the permutations of shared or subst'd drives, etc.) */
4423 newname = map_w32_filename (newname, NULL);
4425 /* volume_info is set indirectly by map_w32_filename. */
4426 newname_dev = volume_info.serialnum;
4428 if (w32_unicode_filenames)
4430 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4432 filename_to_utf16 (temp, temp_w);
4433 filename_to_utf16 (newname, newname_w);
4434 result = _wrename (temp_w, newname_w);
4435 if (result < 0 && force)
4437 DWORD w32err = GetLastError ();
4439 if (errno == EACCES
4440 && newname_dev != oldname_dev)
4442 /* The implementation of `rename' on Windows does not return
4443 errno = EXDEV when you are moving a directory to a
4444 different storage device (ex. logical disk). It returns
4445 EACCES instead. So here we handle such situations and
4446 return EXDEV. */
4447 DWORD attributes;
4449 if ((attributes = GetFileAttributesW (temp_w)) != -1
4450 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4451 errno = EXDEV;
4453 else if (errno == EEXIST)
4455 if (_wchmod (newname_w, 0666) != 0)
4456 return result;
4457 if (_wunlink (newname_w) != 0)
4458 return result;
4459 result = _wrename (temp_w, newname_w);
4461 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4462 && is_symlink (temp))
4464 /* This is Windows prohibiting the user from creating a
4465 symlink in another place, since that requires
4466 privileges. */
4467 errno = EPERM;
4471 else
4473 char newname_a[MAX_PATH];
4475 if (!have_temp_a)
4476 filename_to_ansi (temp, temp_a);
4477 filename_to_ansi (newname, newname_a);
4478 result = rename (temp_a, newname_a);
4479 if (result < 0 && force)
4481 DWORD w32err = GetLastError ();
4483 if (errno == EACCES
4484 && newname_dev != oldname_dev)
4486 DWORD attributes;
4488 if ((attributes = GetFileAttributesA (temp_a)) != -1
4489 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4490 errno = EXDEV;
4492 else if (errno == EEXIST)
4494 if (_chmod (newname_a, 0666) != 0)
4495 return result;
4496 if (_unlink (newname_a) != 0)
4497 return result;
4498 result = rename (temp_a, newname_a);
4500 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4501 && is_symlink (temp))
4502 errno = EPERM;
4506 return result;
4510 sys_rename (char const *old, char const *new)
4512 return sys_rename_replace (old, new, TRUE);
4516 sys_rmdir (const char * path)
4518 path = map_w32_filename (path, NULL);
4520 if (w32_unicode_filenames)
4522 wchar_t path_w[MAX_PATH];
4524 filename_to_utf16 (path, path_w);
4525 return _wrmdir (path_w);
4527 else
4529 char path_a[MAX_PATH];
4531 filename_to_ansi (path, path_a);
4532 return _rmdir (path_a);
4537 sys_unlink (const char * path)
4539 int rmstatus, e;
4541 path = map_w32_filename (path, NULL);
4543 if (w32_unicode_filenames)
4545 wchar_t path_w[MAX_PATH];
4547 filename_to_utf16 (path, path_w);
4548 /* On Unix, unlink works without write permission. */
4549 _wchmod (path_w, 0666);
4550 rmstatus = _wunlink (path_w);
4551 e = errno;
4552 /* Symlinks to directories can only be deleted by _rmdir;
4553 _unlink returns EACCES. */
4554 if (rmstatus != 0
4555 && errno == EACCES
4556 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4557 rmstatus = _wrmdir (path_w);
4558 else
4559 errno = e;
4561 else
4563 char path_a[MAX_PATH];
4565 filename_to_ansi (path, path_a);
4566 _chmod (path_a, 0666);
4567 rmstatus = _unlink (path_a);
4568 e = errno;
4569 if (rmstatus != 0
4570 && errno == EACCES
4571 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4572 rmstatus = _rmdir (path_a);
4573 else
4574 errno = e;
4577 return rmstatus;
4580 static FILETIME utc_base_ft;
4581 static ULONGLONG utc_base; /* In 100ns units */
4582 static int init = 0;
4584 #define FILETIME_TO_U64(result, ft) \
4585 do { \
4586 ULARGE_INTEGER uiTemp; \
4587 uiTemp.LowPart = (ft).dwLowDateTime; \
4588 uiTemp.HighPart = (ft).dwHighDateTime; \
4589 result = uiTemp.QuadPart; \
4590 } while (0)
4592 static void
4593 initialize_utc_base (void)
4595 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4596 SYSTEMTIME st;
4598 st.wYear = 1970;
4599 st.wMonth = 1;
4600 st.wDay = 1;
4601 st.wHour = 0;
4602 st.wMinute = 0;
4603 st.wSecond = 0;
4604 st.wMilliseconds = 0;
4606 SystemTimeToFileTime (&st, &utc_base_ft);
4607 FILETIME_TO_U64 (utc_base, utc_base_ft);
4610 static time_t
4611 convert_time (FILETIME ft)
4613 ULONGLONG tmp;
4615 if (!init)
4617 initialize_utc_base ();
4618 init = 1;
4621 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4622 return 0;
4624 FILETIME_TO_U64 (tmp, ft);
4625 return (time_t) ((tmp - utc_base) / 10000000L);
4628 static void
4629 convert_from_time_t (time_t time, FILETIME * pft)
4631 ULARGE_INTEGER tmp;
4633 if (!init)
4635 initialize_utc_base ();
4636 init = 1;
4639 /* time in 100ns units since 1-Jan-1601 */
4640 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4641 pft->dwHighDateTime = tmp.HighPart;
4642 pft->dwLowDateTime = tmp.LowPart;
4645 static PSECURITY_DESCRIPTOR
4646 get_file_security_desc_by_handle (HANDLE h)
4648 PSECURITY_DESCRIPTOR psd = NULL;
4649 DWORD err;
4650 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4651 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4653 err = get_security_info (h, SE_FILE_OBJECT, si,
4654 NULL, NULL, NULL, NULL, &psd);
4655 if (err != ERROR_SUCCESS)
4656 return NULL;
4658 return psd;
4661 static PSECURITY_DESCRIPTOR
4662 get_file_security_desc_by_name (const char *fname)
4664 PSECURITY_DESCRIPTOR psd = NULL;
4665 DWORD sd_len, err;
4666 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4667 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4669 if (!get_file_security (fname, si, psd, 0, &sd_len))
4671 err = GetLastError ();
4672 if (err != ERROR_INSUFFICIENT_BUFFER)
4673 return NULL;
4676 psd = xmalloc (sd_len);
4677 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4679 xfree (psd);
4680 return NULL;
4683 return psd;
4686 static DWORD
4687 get_rid (PSID sid)
4689 unsigned n_subauthorities;
4691 /* Use the last sub-authority value of the RID, the relative
4692 portion of the SID, as user/group ID. */
4693 n_subauthorities = *get_sid_sub_authority_count (sid);
4694 if (n_subauthorities < 1)
4695 return 0; /* the "World" RID */
4696 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4699 /* Caching SID and account values for faster lokup. */
4701 struct w32_id {
4702 unsigned rid;
4703 struct w32_id *next;
4704 char name[GNLEN+1];
4705 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4708 static struct w32_id *w32_idlist;
4710 static int
4711 w32_cached_id (PSID sid, unsigned *id, char *name)
4713 struct w32_id *tail, *found;
4715 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4717 if (equal_sid ((PSID)tail->sid, sid))
4719 found = tail;
4720 break;
4723 if (found)
4725 *id = found->rid;
4726 strcpy (name, found->name);
4727 return 1;
4729 else
4730 return 0;
4733 static void
4734 w32_add_to_cache (PSID sid, unsigned id, char *name)
4736 DWORD sid_len;
4737 struct w32_id *new_entry;
4739 /* We don't want to leave behind stale cache from when Emacs was
4740 dumped. */
4741 if (initialized)
4743 sid_len = get_length_sid (sid);
4744 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4745 if (new_entry)
4747 new_entry->rid = id;
4748 strcpy (new_entry->name, name);
4749 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4750 new_entry->next = w32_idlist;
4751 w32_idlist = new_entry;
4756 #define UID 1
4757 #define GID 2
4759 static int
4760 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4762 PSID sid = NULL;
4763 BOOL dflt;
4764 SID_NAME_USE ignore;
4765 char name[UNLEN+1];
4766 DWORD name_len = sizeof (name);
4767 char domain[1024];
4768 DWORD domain_len = sizeof (domain);
4769 int use_dflt = 0;
4770 int result;
4772 if (what == UID)
4773 result = get_security_descriptor_owner (psd, &sid, &dflt);
4774 else if (what == GID)
4775 result = get_security_descriptor_group (psd, &sid, &dflt);
4776 else
4777 result = 0;
4779 if (!result || !is_valid_sid (sid))
4780 use_dflt = 1;
4781 else if (!w32_cached_id (sid, id, nm))
4783 if (!lookup_account_sid (NULL, sid, name, &name_len,
4784 domain, &domain_len, &ignore)
4785 || name_len > UNLEN+1)
4786 use_dflt = 1;
4787 else
4789 *id = get_rid (sid);
4790 strcpy (nm, name);
4791 w32_add_to_cache (sid, *id, name);
4794 return use_dflt;
4797 static void
4798 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4800 int dflt_usr = 0, dflt_grp = 0;
4802 if (!psd)
4804 dflt_usr = 1;
4805 dflt_grp = 1;
4807 else
4809 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4810 dflt_usr = 1;
4811 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4812 dflt_grp = 1;
4814 /* Consider files to belong to current user/group, if we cannot get
4815 more accurate information. */
4816 if (dflt_usr)
4818 st->st_uid = dflt_passwd.pw_uid;
4819 strcpy (st->st_uname, dflt_passwd.pw_name);
4821 if (dflt_grp)
4823 st->st_gid = dflt_passwd.pw_gid;
4824 strcpy (st->st_gname, dflt_group.gr_name);
4828 /* Return non-zero if NAME is a potentially slow filesystem. */
4830 is_slow_fs (const char *name)
4832 char drive_root[4];
4833 UINT devtype;
4835 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4836 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4837 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4838 devtype = GetDriveType (NULL); /* use root of current drive */
4839 else
4841 /* GetDriveType needs the root directory of the drive. */
4842 strncpy (drive_root, name, 2);
4843 drive_root[2] = '\\';
4844 drive_root[3] = '\0';
4845 devtype = GetDriveType (drive_root);
4847 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4850 /* If this is non-zero, the caller wants accurate information about
4851 file's owner and group, which could be expensive to get. dired.c
4852 uses this flag when needed for the job at hand. */
4853 int w32_stat_get_owner_group;
4855 /* MSVC stat function can't cope with UNC names and has other bugs, so
4856 replace it with our own. This also allows us to calculate consistent
4857 inode values and owner/group without hacks in the main Emacs code,
4858 and support file names encoded in UTF-8. */
4860 static int
4861 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4863 char *name, *save_name, *r;
4864 WIN32_FIND_DATAW wfd_w;
4865 WIN32_FIND_DATAA wfd_a;
4866 HANDLE fh;
4867 unsigned __int64 fake_inode = 0;
4868 int permission;
4869 int len;
4870 int rootdir = FALSE;
4871 PSECURITY_DESCRIPTOR psd = NULL;
4872 int is_a_symlink = 0;
4873 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4874 DWORD access_rights = 0;
4875 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4876 FILETIME ctime, atime, wtime;
4877 wchar_t name_w[MAX_PATH];
4878 char name_a[MAX_PATH];
4880 if (path == NULL || buf == NULL)
4882 errno = EFAULT;
4883 return -1;
4886 save_name = name = (char *) map_w32_filename (path, &path);
4887 /* Must be valid filename, no wild cards or other invalid
4888 characters. */
4889 if (strpbrk (name, "*?|<>\""))
4891 errno = ENOENT;
4892 return -1;
4895 len = strlen (name);
4896 /* Allocate 1 extra byte so that we could append a slash to a root
4897 directory, down below. */
4898 name = strcpy (alloca (len + 2), name);
4900 /* Avoid a somewhat costly call to is_symlink if the filesystem
4901 doesn't support symlinks. */
4902 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4903 is_a_symlink = is_symlink (name);
4905 /* Plan A: Open the file and get all the necessary information via
4906 the resulting handle. This solves several issues in one blow:
4908 . retrieves attributes for the target of a symlink, if needed
4909 . gets attributes of root directories and symlinks pointing to
4910 root directories, thus avoiding the need for special-casing
4911 these and detecting them by examining the file-name format
4912 . retrieves more accurate attributes (e.g., non-zero size for
4913 some directories, esp. directories that are junction points)
4914 . correctly resolves "c:/..", "/.." and similar file names
4915 . avoids run-time penalties for 99% of use cases
4917 Plan A is always tried first, unless the user asked not to (but
4918 if the file is a symlink and we need to follow links, we try Plan
4919 A even if the user asked not to).
4921 If Plan A fails, we go to Plan B (below), where various
4922 potentially expensive techniques must be used to handle "special"
4923 files such as UNC volumes etc. */
4924 if (!(NILP (Vw32_get_true_file_attributes)
4925 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4926 /* Following symlinks requires getting the info by handle. */
4927 || (is_a_symlink && follow_symlinks))
4929 BY_HANDLE_FILE_INFORMATION info;
4931 if (is_a_symlink && !follow_symlinks)
4932 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4933 /* READ_CONTROL access rights are required to get security info
4934 by handle. But if the OS doesn't support security in the
4935 first place, we don't need to try. */
4936 if (is_windows_9x () != TRUE)
4937 access_rights |= READ_CONTROL;
4939 if (w32_unicode_filenames)
4941 filename_to_utf16 (name, name_w);
4942 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4943 file_flags, NULL);
4944 /* If CreateFile fails with READ_CONTROL, try again with
4945 zero as access rights. */
4946 if (fh == INVALID_HANDLE_VALUE && access_rights)
4947 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4948 file_flags, NULL);
4950 else
4952 filename_to_ansi (name, name_a);
4953 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4954 file_flags, NULL);
4955 if (fh == INVALID_HANDLE_VALUE && access_rights)
4956 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4957 file_flags, NULL);
4959 if (fh == INVALID_HANDLE_VALUE)
4960 goto no_true_file_attributes;
4962 /* This is more accurate in terms of getting the correct number
4963 of links, but is quite slow (it is noticeable when Emacs is
4964 making a list of file name completions). */
4965 if (GetFileInformationByHandle (fh, &info))
4967 nlinks = info.nNumberOfLinks;
4968 /* Might as well use file index to fake inode values, but this
4969 is not guaranteed to be unique unless we keep a handle open
4970 all the time (even then there are situations where it is
4971 not unique). Reputedly, there are at most 48 bits of info
4972 (on NTFS, presumably less on FAT). */
4973 fake_inode = info.nFileIndexHigh;
4974 fake_inode <<= 32;
4975 fake_inode += info.nFileIndexLow;
4976 serialnum = info.dwVolumeSerialNumber;
4977 fs_high = info.nFileSizeHigh;
4978 fs_low = info.nFileSizeLow;
4979 ctime = info.ftCreationTime;
4980 atime = info.ftLastAccessTime;
4981 wtime = info.ftLastWriteTime;
4982 fattrs = info.dwFileAttributes;
4984 else
4986 /* We don't go to Plan B here, because it's not clear that
4987 it's a good idea. The only known use case where
4988 CreateFile succeeds, but GetFileInformationByHandle fails
4989 (with ERROR_INVALID_FUNCTION) is for character devices
4990 such as NUL, PRN, etc. For these, switching to Plan B is
4991 a net loss, because we lose the character device
4992 attribute returned by GetFileType below (FindFirstFile
4993 doesn't set that bit in the attributes), and the other
4994 fields don't make sense for character devices anyway.
4995 Emacs doesn't really care for non-file entities in the
4996 context of l?stat, so neither do we. */
4998 /* w32err is assigned so one could put a breakpoint here and
4999 examine its value, when GetFileInformationByHandle
5000 fails. */
5001 DWORD w32err = GetLastError ();
5003 switch (w32err)
5005 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5006 errno = ENOENT;
5007 return -1;
5011 /* Test for a symlink before testing for a directory, since
5012 symlinks to directories have the directory bit set, but we
5013 don't want them to appear as directories. */
5014 if (is_a_symlink && !follow_symlinks)
5015 buf->st_mode = S_IFLNK;
5016 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5017 buf->st_mode = S_IFDIR;
5018 else
5020 DWORD ftype = GetFileType (fh);
5022 switch (ftype)
5024 case FILE_TYPE_DISK:
5025 buf->st_mode = S_IFREG;
5026 break;
5027 case FILE_TYPE_PIPE:
5028 buf->st_mode = S_IFIFO;
5029 break;
5030 case FILE_TYPE_CHAR:
5031 case FILE_TYPE_UNKNOWN:
5032 default:
5033 buf->st_mode = S_IFCHR;
5036 /* We produce the fallback owner and group data, based on the
5037 current user that runs Emacs, in the following cases:
5039 . caller didn't request owner and group info
5040 . this is Windows 9X
5041 . getting security by handle failed, and we need to produce
5042 information for the target of a symlink (this is better
5043 than producing a potentially misleading info about the
5044 symlink itself)
5046 If getting security by handle fails, and we don't need to
5047 resolve symlinks, we try getting security by name. */
5048 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5049 get_file_owner_and_group (NULL, buf);
5050 else
5052 psd = get_file_security_desc_by_handle (fh);
5053 if (psd)
5055 get_file_owner_and_group (psd, buf);
5056 LocalFree (psd);
5058 else if (!(is_a_symlink && follow_symlinks))
5060 psd = get_file_security_desc_by_name (name);
5061 get_file_owner_and_group (psd, buf);
5062 xfree (psd);
5064 else
5065 get_file_owner_and_group (NULL, buf);
5067 CloseHandle (fh);
5069 else
5071 no_true_file_attributes:
5072 /* Plan B: Either getting a handle on the file failed, or the
5073 caller explicitly asked us to not bother making this
5074 information more accurate.
5076 Implementation note: In Plan B, we never bother to resolve
5077 symlinks, even if we got here because we tried Plan A and
5078 failed. That's because, even if the caller asked for extra
5079 precision by setting Vw32_get_true_file_attributes to t,
5080 resolving symlinks requires acquiring a file handle to the
5081 symlink, which we already know will fail. And if the user
5082 did not ask for extra precision, resolving symlinks will fly
5083 in the face of that request, since the user then wants the
5084 lightweight version of the code. */
5085 rootdir = (path >= save_name + len - 1
5086 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5088 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5089 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5090 if (IS_DIRECTORY_SEP (r[0])
5091 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5092 r[1] = r[2] = '\0';
5094 /* Note: If NAME is a symlink to the root of a UNC volume
5095 (i.e. "\\SERVER"), we will not detect that here, and we will
5096 return data about the symlink as result of FindFirst below.
5097 This is unfortunate, but that marginal use case does not
5098 justify a call to chase_symlinks which would impose a penalty
5099 on all the other use cases. (We get here for symlinks to
5100 roots of UNC volumes because CreateFile above fails for them,
5101 unlike with symlinks to root directories X:\ of drives.) */
5102 if (is_unc_volume (name))
5104 fattrs = unc_volume_file_attributes (name);
5105 if (fattrs == -1)
5106 return -1;
5108 ctime = atime = wtime = utc_base_ft;
5110 else if (rootdir)
5112 /* Make sure root directories end in a slash. */
5113 if (!IS_DIRECTORY_SEP (name[len-1]))
5114 strcpy (name + len, "\\");
5115 if (GetDriveType (name) < 2)
5117 errno = ENOENT;
5118 return -1;
5121 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5122 ctime = atime = wtime = utc_base_ft;
5124 else
5126 int have_wfd = -1;
5128 /* Make sure non-root directories do NOT end in a slash,
5129 otherwise FindFirstFile might fail. */
5130 if (IS_DIRECTORY_SEP (name[len-1]))
5131 name[len - 1] = 0;
5133 /* (This is hacky, but helps when doing file completions on
5134 network drives.) Optimize by using information available from
5135 active readdir if possible. */
5136 len = strlen (dir_pathname);
5137 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5138 len--;
5139 if (dir_find_handle != INVALID_HANDLE_VALUE
5140 && last_dir_find_data != -1
5141 && !(is_a_symlink && follow_symlinks)
5142 /* The 2 file-name comparisons below support only ASCII
5143 characters, and will lose (compare not equal) when
5144 the file names include non-ASCII characters that are
5145 the same but for the case. However, doing this
5146 properly involves: (a) converting both file names to
5147 UTF-16, (b) lower-casing both names using CharLowerW,
5148 and (c) comparing the results; this would be quite a
5149 bit slower, whereas Plan B is for users who want
5150 lightweight albeit inaccurate version of 'stat'. */
5151 && c_strncasecmp (save_name, dir_pathname, len) == 0
5152 && IS_DIRECTORY_SEP (name[len])
5153 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5155 have_wfd = last_dir_find_data;
5156 /* This was the last entry returned by readdir. */
5157 if (last_dir_find_data == DIR_FIND_DATA_W)
5158 wfd_w = dir_find_data_w;
5159 else
5160 wfd_a = dir_find_data_a;
5162 else
5164 logon_network_drive (name);
5166 if (w32_unicode_filenames)
5168 filename_to_utf16 (name, name_w);
5169 fh = FindFirstFileW (name_w, &wfd_w);
5170 have_wfd = DIR_FIND_DATA_W;
5172 else
5174 filename_to_ansi (name, name_a);
5175 /* If NAME includes characters not representable by
5176 the current ANSI codepage, filename_to_ansi
5177 usually replaces them with a '?'. We don't want
5178 to let FindFirstFileA interpret those as wildcards,
5179 and "succeed", returning us data from some random
5180 file in the same directory. */
5181 if (_mbspbrk (name_a, "?"))
5182 fh = INVALID_HANDLE_VALUE;
5183 else
5184 fh = FindFirstFileA (name_a, &wfd_a);
5185 have_wfd = DIR_FIND_DATA_A;
5187 if (fh == INVALID_HANDLE_VALUE)
5189 errno = ENOENT;
5190 return -1;
5192 FindClose (fh);
5194 /* Note: if NAME is a symlink, the information we get from
5195 FindFirstFile is for the symlink, not its target. */
5196 if (have_wfd == DIR_FIND_DATA_W)
5198 fattrs = wfd_w.dwFileAttributes;
5199 ctime = wfd_w.ftCreationTime;
5200 atime = wfd_w.ftLastAccessTime;
5201 wtime = wfd_w.ftLastWriteTime;
5202 fs_high = wfd_w.nFileSizeHigh;
5203 fs_low = wfd_w.nFileSizeLow;
5205 else
5207 fattrs = wfd_a.dwFileAttributes;
5208 ctime = wfd_a.ftCreationTime;
5209 atime = wfd_a.ftLastAccessTime;
5210 wtime = wfd_a.ftLastWriteTime;
5211 fs_high = wfd_a.nFileSizeHigh;
5212 fs_low = wfd_a.nFileSizeLow;
5214 fake_inode = 0;
5215 nlinks = 1;
5216 serialnum = volume_info.serialnum;
5218 if (is_a_symlink && !follow_symlinks)
5219 buf->st_mode = S_IFLNK;
5220 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5221 buf->st_mode = S_IFDIR;
5222 else
5223 buf->st_mode = S_IFREG;
5225 get_file_owner_and_group (NULL, buf);
5228 buf->st_ino = fake_inode;
5230 buf->st_dev = serialnum;
5231 buf->st_rdev = serialnum;
5233 buf->st_size = fs_high;
5234 buf->st_size <<= 32;
5235 buf->st_size += fs_low;
5236 buf->st_nlink = nlinks;
5238 /* Convert timestamps to Unix format. */
5239 buf->st_mtime = convert_time (wtime);
5240 buf->st_atime = convert_time (atime);
5241 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5242 buf->st_ctime = convert_time (ctime);
5243 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5245 /* determine rwx permissions */
5246 if (is_a_symlink && !follow_symlinks)
5247 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5248 else
5250 if (fattrs & FILE_ATTRIBUTE_READONLY)
5251 permission = S_IREAD;
5252 else
5253 permission = S_IREAD | S_IWRITE;
5255 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5256 permission |= S_IEXEC;
5257 else if (is_exec (name))
5258 permission |= S_IEXEC;
5261 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5263 return 0;
5267 stat (const char * path, struct stat * buf)
5269 return stat_worker (path, buf, 1);
5273 lstat (const char * path, struct stat * buf)
5275 return stat_worker (path, buf, 0);
5279 fstatat (int fd, char const *name, struct stat *st, int flags)
5281 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5282 This is good enough for the current usage in Emacs, but is fragile.
5284 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5285 Gnulib does this and can serve as a model. */
5286 char fullname[MAX_UTF8_PATH];
5288 if (fd != AT_FDCWD)
5290 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5292 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5293 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5294 < 0)
5296 errno = ENAMETOOLONG;
5297 return -1;
5299 name = fullname;
5302 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5305 /* Provide fstat and utime as well as stat for consistent handling of
5306 file timestamps. */
5308 fstat (int desc, struct stat * buf)
5310 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5311 BY_HANDLE_FILE_INFORMATION info;
5312 unsigned __int64 fake_inode;
5313 int permission;
5315 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5317 case FILE_TYPE_DISK:
5318 buf->st_mode = S_IFREG;
5319 if (!GetFileInformationByHandle (fh, &info))
5321 errno = EACCES;
5322 return -1;
5324 break;
5325 case FILE_TYPE_PIPE:
5326 buf->st_mode = S_IFIFO;
5327 goto non_disk;
5328 case FILE_TYPE_CHAR:
5329 case FILE_TYPE_UNKNOWN:
5330 default:
5331 buf->st_mode = S_IFCHR;
5332 non_disk:
5333 memset (&info, 0, sizeof (info));
5334 info.dwFileAttributes = 0;
5335 info.ftCreationTime = utc_base_ft;
5336 info.ftLastAccessTime = utc_base_ft;
5337 info.ftLastWriteTime = utc_base_ft;
5340 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5341 buf->st_mode = S_IFDIR;
5343 buf->st_nlink = info.nNumberOfLinks;
5344 /* Might as well use file index to fake inode values, but this
5345 is not guaranteed to be unique unless we keep a handle open
5346 all the time (even then there are situations where it is
5347 not unique). Reputedly, there are at most 48 bits of info
5348 (on NTFS, presumably less on FAT). */
5349 fake_inode = info.nFileIndexHigh;
5350 fake_inode <<= 32;
5351 fake_inode += info.nFileIndexLow;
5353 /* MSVC defines _ino_t to be short; other libc's might not. */
5354 if (sizeof (buf->st_ino) == 2)
5355 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5356 else
5357 buf->st_ino = fake_inode;
5359 /* If the caller so requested, get the true file owner and group.
5360 Otherwise, consider the file to belong to the current user. */
5361 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5362 get_file_owner_and_group (NULL, buf);
5363 else
5365 PSECURITY_DESCRIPTOR psd = NULL;
5367 psd = get_file_security_desc_by_handle (fh);
5368 if (psd)
5370 get_file_owner_and_group (psd, buf);
5371 LocalFree (psd);
5373 else
5374 get_file_owner_and_group (NULL, buf);
5377 buf->st_dev = info.dwVolumeSerialNumber;
5378 buf->st_rdev = info.dwVolumeSerialNumber;
5380 buf->st_size = info.nFileSizeHigh;
5381 buf->st_size <<= 32;
5382 buf->st_size += info.nFileSizeLow;
5384 /* Convert timestamps to Unix format. */
5385 buf->st_mtime = convert_time (info.ftLastWriteTime);
5386 buf->st_atime = convert_time (info.ftLastAccessTime);
5387 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5388 buf->st_ctime = convert_time (info.ftCreationTime);
5389 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5391 /* determine rwx permissions */
5392 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5393 permission = S_IREAD;
5394 else
5395 permission = S_IREAD | S_IWRITE;
5397 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5398 permission |= S_IEXEC;
5399 else
5401 #if 0 /* no way of knowing the filename */
5402 char * p = strrchr (name, '.');
5403 if (p != NULL &&
5404 (xstrcasecmp (p, ".exe") == 0 ||
5405 xstrcasecmp (p, ".com") == 0 ||
5406 xstrcasecmp (p, ".bat") == 0 ||
5407 xstrcasecmp (p, ".cmd") == 0))
5408 permission |= S_IEXEC;
5409 #endif
5412 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5414 return 0;
5417 /* A version of 'utime' which handles directories as well as
5418 files. */
5421 utime (const char *name, struct utimbuf *times)
5423 struct utimbuf deftime;
5424 HANDLE fh;
5425 FILETIME mtime;
5426 FILETIME atime;
5428 if (times == NULL)
5430 deftime.modtime = deftime.actime = time (NULL);
5431 times = &deftime;
5434 if (w32_unicode_filenames)
5436 wchar_t name_utf16[MAX_PATH];
5438 if (filename_to_utf16 (name, name_utf16) != 0)
5439 return -1; /* errno set by filename_to_utf16 */
5441 /* Need write access to set times. */
5442 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5443 /* If NAME specifies a directory, FILE_SHARE_DELETE
5444 allows other processes to delete files inside it,
5445 while we have the directory open. */
5446 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5447 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5449 else
5451 char name_ansi[MAX_PATH];
5453 if (filename_to_ansi (name, name_ansi) != 0)
5454 return -1; /* errno set by filename_to_ansi */
5456 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5457 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5458 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5460 if (fh != INVALID_HANDLE_VALUE)
5462 convert_from_time_t (times->actime, &atime);
5463 convert_from_time_t (times->modtime, &mtime);
5464 if (!SetFileTime (fh, NULL, &atime, &mtime))
5466 CloseHandle (fh);
5467 errno = EACCES;
5468 return -1;
5470 CloseHandle (fh);
5472 else
5474 DWORD err = GetLastError ();
5476 switch (err)
5478 case ERROR_FILE_NOT_FOUND:
5479 case ERROR_PATH_NOT_FOUND:
5480 case ERROR_INVALID_DRIVE:
5481 case ERROR_BAD_NETPATH:
5482 case ERROR_DEV_NOT_EXIST:
5483 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5484 file name includes ?s, i.e. translation to ANSI failed. */
5485 case ERROR_INVALID_NAME:
5486 errno = ENOENT;
5487 break;
5488 case ERROR_TOO_MANY_OPEN_FILES:
5489 errno = ENFILE;
5490 break;
5491 case ERROR_ACCESS_DENIED:
5492 case ERROR_SHARING_VIOLATION:
5493 errno = EACCES;
5494 break;
5495 default:
5496 errno = EINVAL;
5497 break;
5499 return -1;
5501 return 0;
5505 sys_umask (int mode)
5507 static int current_mask;
5508 int retval, arg = 0;
5510 /* The only bit we really support is the write bit. Files are
5511 always readable on MS-Windows, and the execute bit does not exist
5512 at all. */
5513 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5514 to prevent access by other users on NTFS. */
5515 if ((mode & S_IWRITE) != 0)
5516 arg |= S_IWRITE;
5518 retval = _umask (arg);
5519 /* Merge into the return value the bits they've set the last time,
5520 which msvcrt.dll ignores and never returns. Emacs insists on its
5521 notion of mask being identical to what we return. */
5522 retval |= (current_mask & ~S_IWRITE);
5523 current_mask = mode;
5525 return retval;
5529 /* Symlink-related functions. */
5530 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5531 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5532 #endif
5535 symlink (char const *filename, char const *linkname)
5537 char linkfn[MAX_UTF8_PATH], *tgtfn;
5538 DWORD flags = 0;
5539 int dir_access, filename_ends_in_slash;
5541 /* Diagnostics follows Posix as much as possible. */
5542 if (filename == NULL || linkname == NULL)
5544 errno = EFAULT;
5545 return -1;
5547 if (!*filename)
5549 errno = ENOENT;
5550 return -1;
5552 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5554 errno = ENAMETOOLONG;
5555 return -1;
5558 strcpy (linkfn, map_w32_filename (linkname, NULL));
5559 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5561 errno = EPERM;
5562 return -1;
5565 /* Note: since empty FILENAME was already rejected, we can safely
5566 refer to FILENAME[1]. */
5567 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5569 /* Non-absolute FILENAME is understood as being relative to
5570 LINKNAME's directory. We need to prepend that directory to
5571 FILENAME to get correct results from faccessat below, since
5572 otherwise it will interpret FILENAME relative to the
5573 directory where the Emacs process runs. Note that
5574 make-symbolic-link always makes sure LINKNAME is a fully
5575 expanded file name. */
5576 char tem[MAX_UTF8_PATH];
5577 char *p = linkfn + strlen (linkfn);
5579 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5580 p--;
5581 if (p > linkfn)
5582 strncpy (tem, linkfn, p - linkfn);
5583 strcpy (tem + (p - linkfn), filename);
5584 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5586 else
5587 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5589 /* Since Windows distinguishes between symlinks to directories and
5590 to files, we provide a kludgy feature: if FILENAME doesn't
5591 exist, but ends in a slash, we create a symlink to directory. If
5592 FILENAME exists and is a directory, we always create a symlink to
5593 directory. */
5594 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5595 if (dir_access == 0 || filename_ends_in_slash)
5596 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5598 tgtfn = (char *)map_w32_filename (filename, NULL);
5599 if (filename_ends_in_slash)
5600 tgtfn[strlen (tgtfn) - 1] = '\0';
5602 errno = 0;
5603 if (!create_symbolic_link (linkfn, tgtfn, flags))
5605 /* ENOSYS is set by create_symbolic_link, when it detects that
5606 the OS doesn't support the CreateSymbolicLink API. */
5607 if (errno != ENOSYS)
5609 DWORD w32err = GetLastError ();
5611 switch (w32err)
5613 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5614 TGTFN point to the same file name, go figure. */
5615 case ERROR_SUCCESS:
5616 case ERROR_FILE_EXISTS:
5617 errno = EEXIST;
5618 break;
5619 case ERROR_ACCESS_DENIED:
5620 errno = EACCES;
5621 break;
5622 case ERROR_FILE_NOT_FOUND:
5623 case ERROR_PATH_NOT_FOUND:
5624 case ERROR_BAD_NETPATH:
5625 case ERROR_INVALID_REPARSE_DATA:
5626 errno = ENOENT;
5627 break;
5628 case ERROR_DIRECTORY:
5629 errno = EISDIR;
5630 break;
5631 case ERROR_PRIVILEGE_NOT_HELD:
5632 case ERROR_NOT_ALL_ASSIGNED:
5633 errno = EPERM;
5634 break;
5635 case ERROR_DISK_FULL:
5636 errno = ENOSPC;
5637 break;
5638 default:
5639 errno = EINVAL;
5640 break;
5643 return -1;
5645 return 0;
5648 /* A quick inexpensive test of whether FILENAME identifies a file that
5649 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5650 must already be in the normalized form returned by
5651 map_w32_filename. If the symlink is to a directory, the
5652 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5654 Note: for repeated operations on many files, it is best to test
5655 whether the underlying volume actually supports symlinks, by
5656 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5657 avoid the call to this function if it doesn't. That's because the
5658 call to GetFileAttributes takes a non-negligible time, especially
5659 on non-local or removable filesystems. See stat_worker for an
5660 example of how to do that. */
5661 static int
5662 is_symlink (const char *filename)
5664 DWORD attrs;
5665 wchar_t filename_w[MAX_PATH];
5666 char filename_a[MAX_PATH];
5667 WIN32_FIND_DATAW wfdw;
5668 WIN32_FIND_DATAA wfda;
5669 HANDLE fh;
5670 int attrs_mean_symlink;
5672 if (w32_unicode_filenames)
5674 filename_to_utf16 (filename, filename_w);
5675 attrs = GetFileAttributesW (filename_w);
5677 else
5679 filename_to_ansi (filename, filename_a);
5680 attrs = GetFileAttributesA (filename_a);
5682 if (attrs == -1)
5684 DWORD w32err = GetLastError ();
5686 switch (w32err)
5688 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5689 break;
5690 case ERROR_ACCESS_DENIED:
5691 errno = EACCES;
5692 break;
5693 case ERROR_FILE_NOT_FOUND:
5694 case ERROR_PATH_NOT_FOUND:
5695 default:
5696 errno = ENOENT;
5697 break;
5699 return 0;
5701 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5702 return 0;
5703 logon_network_drive (filename);
5704 if (w32_unicode_filenames)
5706 fh = FindFirstFileW (filename_w, &wfdw);
5707 attrs_mean_symlink =
5708 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5709 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5710 if (attrs_mean_symlink)
5711 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5713 else if (_mbspbrk (filename_a, "?"))
5715 /* filename_to_ansi failed to convert the file name. */
5716 errno = ENOENT;
5717 return 0;
5719 else
5721 fh = FindFirstFileA (filename_a, &wfda);
5722 attrs_mean_symlink =
5723 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5724 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5725 if (attrs_mean_symlink)
5726 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5728 if (fh == INVALID_HANDLE_VALUE)
5729 return 0;
5730 FindClose (fh);
5731 return attrs_mean_symlink;
5734 /* If NAME identifies a symbolic link, copy into BUF the file name of
5735 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5736 null-terminate the target name, even if it fits. Return the number
5737 of bytes copied, or -1 if NAME is not a symlink or any error was
5738 encountered while resolving it. The file name copied into BUF is
5739 encoded in the current ANSI codepage. */
5740 ssize_t
5741 readlink (const char *name, char *buf, size_t buf_size)
5743 const char *path;
5744 TOKEN_PRIVILEGES privs;
5745 int restore_privs = 0;
5746 HANDLE sh;
5747 ssize_t retval;
5748 char resolved[MAX_UTF8_PATH];
5750 if (name == NULL)
5752 errno = EFAULT;
5753 return -1;
5755 if (!*name)
5757 errno = ENOENT;
5758 return -1;
5761 path = map_w32_filename (name, NULL);
5763 if (strlen (path) > MAX_UTF8_PATH)
5765 errno = ENAMETOOLONG;
5766 return -1;
5769 errno = 0;
5770 if (is_windows_9x () == TRUE
5771 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5772 || !is_symlink (path))
5774 if (!errno)
5775 errno = EINVAL; /* not a symlink */
5776 return -1;
5779 /* Done with simple tests, now we're in for some _real_ work. */
5780 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5781 restore_privs = 1;
5782 /* Implementation note: From here and onward, don't return early,
5783 since that will fail to restore the original set of privileges of
5784 the calling thread. */
5786 retval = -1; /* not too optimistic, are we? */
5788 /* Note: In the next call to CreateFile, we use zero as the 2nd
5789 argument because, when the symlink is a hidden/system file,
5790 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5791 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5792 and directory symlinks. */
5793 if (w32_unicode_filenames)
5795 wchar_t path_w[MAX_PATH];
5797 filename_to_utf16 (path, path_w);
5798 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5799 FILE_FLAG_OPEN_REPARSE_POINT
5800 | FILE_FLAG_BACKUP_SEMANTICS,
5801 NULL);
5803 else
5805 char path_a[MAX_PATH];
5807 filename_to_ansi (path, path_a);
5808 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5809 FILE_FLAG_OPEN_REPARSE_POINT
5810 | FILE_FLAG_BACKUP_SEMANTICS,
5811 NULL);
5813 if (sh != INVALID_HANDLE_VALUE)
5815 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5816 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5817 DWORD retbytes;
5819 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5820 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5821 &retbytes, NULL))
5822 errno = EIO;
5823 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5824 errno = EINVAL;
5825 else
5827 /* Copy the link target name, in wide characters, from
5828 reparse_data, then convert it to multibyte encoding in
5829 the current locale's codepage. */
5830 WCHAR *lwname;
5831 size_t lname_size;
5832 USHORT lwname_len =
5833 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5834 WCHAR *lwname_src =
5835 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5836 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5837 size_t size_to_copy = buf_size;
5839 /* According to MSDN, PrintNameLength does not include the
5840 terminating null character. */
5841 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5842 memcpy (lwname, lwname_src, lwname_len);
5843 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5844 filename_from_utf16 (lwname, resolved);
5845 dostounix_filename (resolved);
5846 lname_size = strlen (resolved) + 1;
5847 if (lname_size <= buf_size)
5848 size_to_copy = lname_size;
5849 strncpy (buf, resolved, size_to_copy);
5850 /* Success! */
5851 retval = size_to_copy;
5853 CloseHandle (sh);
5855 else
5857 /* CreateFile failed. */
5858 DWORD w32err2 = GetLastError ();
5860 switch (w32err2)
5862 case ERROR_FILE_NOT_FOUND:
5863 case ERROR_PATH_NOT_FOUND:
5864 errno = ENOENT;
5865 break;
5866 case ERROR_ACCESS_DENIED:
5867 case ERROR_TOO_MANY_OPEN_FILES:
5868 errno = EACCES;
5869 break;
5870 default:
5871 errno = EPERM;
5872 break;
5875 if (restore_privs)
5877 restore_privilege (&privs);
5878 revert_to_self ();
5881 return retval;
5884 ssize_t
5885 readlinkat (int fd, char const *name, char *buffer,
5886 size_t buffer_size)
5888 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5889 as in fstatat. FIXME: Add proper support for readlinkat. */
5890 char fullname[MAX_UTF8_PATH];
5892 if (fd != AT_FDCWD)
5894 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5895 < 0)
5897 errno = ENAMETOOLONG;
5898 return -1;
5900 name = fullname;
5903 return readlink (name, buffer, buffer_size);
5906 /* If FILE is a symlink, return its target (stored in a static
5907 buffer); otherwise return FILE.
5909 This function repeatedly resolves symlinks in the last component of
5910 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5911 until it arrives at a file whose last component is not a symlink,
5912 or some error occurs. It returns the target of the last
5913 successfully resolved symlink in the chain. If it succeeds to
5914 resolve even a single symlink, the value returned is an absolute
5915 file name with backslashes (result of GetFullPathName). By
5916 contrast, if the original FILE is returned, it is unaltered.
5918 Note: This function can set errno even if it succeeds.
5920 Implementation note: we only resolve the last portion ("basename")
5921 of the argument FILE and of each following file in the chain,
5922 disregarding any possible symlinks in its leading directories.
5923 This is because Windows system calls and library functions
5924 transparently resolve symlinks in leading directories and return
5925 correct information, as long as the basename is not a symlink. */
5926 static char *
5927 chase_symlinks (const char *file)
5929 static char target[MAX_UTF8_PATH];
5930 char link[MAX_UTF8_PATH];
5931 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5932 char target_a[MAX_PATH], link_a[MAX_PATH];
5933 ssize_t res, link_len;
5934 int loop_count = 0;
5936 if (is_windows_9x () == TRUE || !is_symlink (file))
5937 return (char *)file;
5939 if (w32_unicode_filenames)
5941 wchar_t file_w[MAX_PATH];
5943 filename_to_utf16 (file, file_w);
5944 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5945 return (char *)file;
5946 filename_from_utf16 (link_w, link);
5948 else
5950 char file_a[MAX_PATH];
5952 filename_to_ansi (file, file_a);
5953 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5954 return (char *)file;
5955 filename_from_ansi (link_a, link);
5957 link_len = strlen (link);
5959 target[0] = '\0';
5960 do {
5962 /* Remove trailing slashes, as we want to resolve the last
5963 non-trivial part of the link name. */
5964 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5965 link[link_len--] = '\0';
5967 res = readlink (link, target, MAX_UTF8_PATH);
5968 if (res > 0)
5970 target[res] = '\0';
5971 if (!(IS_DEVICE_SEP (target[1])
5972 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5974 /* Target is relative. Append it to the directory part of
5975 the symlink, then copy the result back to target. */
5976 char *p = link + link_len;
5978 while (p > link && !IS_ANY_SEP (p[-1]))
5979 p--;
5980 strcpy (p, target);
5981 strcpy (target, link);
5983 /* Resolve any "." and ".." to get a fully-qualified file name
5984 in link[] again. */
5985 if (w32_unicode_filenames)
5987 filename_to_utf16 (target, target_w);
5988 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5989 if (link_len > 0)
5990 filename_from_utf16 (link_w, link);
5992 else
5994 filename_to_ansi (target, target_a);
5995 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5996 if (link_len > 0)
5997 filename_from_ansi (link_a, link);
5999 link_len = strlen (link);
6001 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6003 if (loop_count > 100)
6004 errno = ELOOP;
6006 if (target[0] == '\0') /* not a single call to readlink succeeded */
6007 return (char *)file;
6008 return target;
6012 /* Posix ACL emulation. */
6015 acl_valid (acl_t acl)
6017 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6020 char *
6021 acl_to_text (acl_t acl, ssize_t *size)
6023 LPTSTR str_acl;
6024 SECURITY_INFORMATION flags =
6025 OWNER_SECURITY_INFORMATION |
6026 GROUP_SECURITY_INFORMATION |
6027 DACL_SECURITY_INFORMATION;
6028 char *retval = NULL;
6029 ULONG local_size;
6030 int e = errno;
6032 errno = 0;
6034 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6036 errno = e;
6037 /* We don't want to mix heaps, so we duplicate the string in our
6038 heap and free the one allocated by the API. */
6039 retval = xstrdup (str_acl);
6040 if (size)
6041 *size = local_size;
6042 LocalFree (str_acl);
6044 else if (errno != ENOTSUP)
6045 errno = EINVAL;
6047 return retval;
6050 acl_t
6051 acl_from_text (const char *acl_str)
6053 PSECURITY_DESCRIPTOR psd, retval = NULL;
6054 ULONG sd_size;
6055 int e = errno;
6057 errno = 0;
6059 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6061 errno = e;
6062 retval = xmalloc (sd_size);
6063 memcpy (retval, psd, sd_size);
6064 LocalFree (psd);
6066 else if (errno != ENOTSUP)
6067 errno = EINVAL;
6069 return retval;
6073 acl_free (void *ptr)
6075 xfree (ptr);
6076 return 0;
6079 acl_t
6080 acl_get_file (const char *fname, acl_type_t type)
6082 PSECURITY_DESCRIPTOR psd = NULL;
6083 const char *filename;
6085 if (type == ACL_TYPE_ACCESS)
6087 DWORD sd_len, err;
6088 SECURITY_INFORMATION si =
6089 OWNER_SECURITY_INFORMATION |
6090 GROUP_SECURITY_INFORMATION |
6091 DACL_SECURITY_INFORMATION ;
6092 int e = errno;
6094 filename = map_w32_filename (fname, NULL);
6095 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6096 fname = chase_symlinks (filename);
6097 else
6098 fname = filename;
6100 errno = 0;
6101 if (!get_file_security (fname, si, psd, 0, &sd_len)
6102 && errno != ENOTSUP)
6104 err = GetLastError ();
6105 if (err == ERROR_INSUFFICIENT_BUFFER)
6107 psd = xmalloc (sd_len);
6108 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6110 xfree (psd);
6111 errno = EIO;
6112 psd = NULL;
6115 else if (err == ERROR_FILE_NOT_FOUND
6116 || err == ERROR_PATH_NOT_FOUND
6117 /* ERROR_INVALID_NAME is what we get if
6118 w32-unicode-filenames is nil and the file cannot
6119 be encoded in the current ANSI codepage. */
6120 || err == ERROR_INVALID_NAME)
6121 errno = ENOENT;
6122 else
6123 errno = EIO;
6125 else if (!errno)
6126 errno = e;
6128 else if (type != ACL_TYPE_DEFAULT)
6129 errno = EINVAL;
6131 return psd;
6135 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6137 TOKEN_PRIVILEGES old1, old2;
6138 DWORD err;
6139 int st = 0, retval = -1;
6140 SECURITY_INFORMATION flags = 0;
6141 PSID psidOwner, psidGroup;
6142 PACL pacl;
6143 BOOL dflt;
6144 BOOL dacl_present;
6145 int e;
6146 const char *filename;
6148 if (acl_valid (acl) != 0
6149 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6151 errno = EINVAL;
6152 return -1;
6155 if (type == ACL_TYPE_DEFAULT)
6157 errno = ENOSYS;
6158 return -1;
6161 filename = map_w32_filename (fname, NULL);
6162 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6163 fname = chase_symlinks (filename);
6164 else
6165 fname = filename;
6167 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6168 &dflt)
6169 && psidOwner)
6170 flags |= OWNER_SECURITY_INFORMATION;
6171 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6172 &dflt)
6173 && psidGroup)
6174 flags |= GROUP_SECURITY_INFORMATION;
6175 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6176 &pacl, &dflt)
6177 && dacl_present)
6178 flags |= DACL_SECURITY_INFORMATION;
6179 if (!flags)
6180 return 0;
6182 /* According to KB-245153, setting the owner will succeed if either:
6183 (1) the caller is the user who will be the new owner, and has the
6184 SE_TAKE_OWNERSHIP privilege, or
6185 (2) the caller has the SE_RESTORE privilege, in which case she can
6186 set any valid user or group as the owner
6188 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6189 privileges, and disregard any failures in obtaining them. If
6190 these privileges cannot be obtained, and do not already exist in
6191 the calling thread's security token, this function could fail
6192 with EPERM. */
6193 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6194 st++;
6195 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6196 st++;
6198 e = errno;
6199 errno = 0;
6200 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6201 DACL inheritance is involved, but it seems to preserve ownership
6202 better than SetNamedSecurityInfo, which is important e.g., in
6203 copy-file. */
6204 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6206 err = GetLastError ();
6208 if (errno != ENOTSUP)
6209 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6210 psidOwner, psidGroup, pacl, NULL);
6212 else
6213 err = ERROR_SUCCESS;
6214 if (err != ERROR_SUCCESS)
6216 if (errno == ENOTSUP)
6218 else if (err == ERROR_INVALID_OWNER
6219 || err == ERROR_NOT_ALL_ASSIGNED
6220 || err == ERROR_ACCESS_DENIED)
6222 /* Maybe the requested ACL and the one the file already has
6223 are identical, in which case we can silently ignore the
6224 failure. (And no, Windows doesn't.) */
6225 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6227 errno = EPERM;
6228 if (current_acl)
6230 char *acl_from = acl_to_text (current_acl, NULL);
6231 char *acl_to = acl_to_text (acl, NULL);
6233 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6235 retval = 0;
6236 errno = e;
6238 if (acl_from)
6239 acl_free (acl_from);
6240 if (acl_to)
6241 acl_free (acl_to);
6242 acl_free (current_acl);
6245 else if (err == ERROR_FILE_NOT_FOUND
6246 || err == ERROR_PATH_NOT_FOUND
6247 /* ERROR_INVALID_NAME is what we get if
6248 w32-unicode-filenames is nil and the file cannot be
6249 encoded in the current ANSI codepage. */
6250 || err == ERROR_INVALID_NAME)
6251 errno = ENOENT;
6252 else
6253 errno = EACCES;
6255 else
6257 retval = 0;
6258 errno = e;
6261 if (st)
6263 if (st >= 2)
6264 restore_privilege (&old2);
6265 restore_privilege (&old1);
6266 revert_to_self ();
6269 return retval;
6273 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6274 have a fixed max size for file names, so we don't need the kind of
6275 alloc/malloc/realloc dance the gnulib version does. We also don't
6276 support FD-relative symlinks. */
6277 char *
6278 careadlinkat (int fd, char const *filename,
6279 char *buffer, size_t buffer_size,
6280 struct allocator const *alloc,
6281 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6283 char linkname[MAX_UTF8_PATH];
6284 ssize_t link_size;
6286 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6288 if (link_size > 0)
6290 char *retval = buffer;
6292 linkname[link_size++] = '\0';
6293 if (link_size > buffer_size)
6294 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6295 if (retval)
6296 memcpy (retval, linkname, link_size);
6298 return retval;
6300 return NULL;
6304 w32_copy_file (const char *from, const char *to,
6305 int keep_time, int preserve_ownership, int copy_acls)
6307 acl_t acl = NULL;
6308 BOOL copy_result;
6309 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6310 char from_a[MAX_PATH], to_a[MAX_PATH];
6312 /* We ignore preserve_ownership for now. */
6313 preserve_ownership = preserve_ownership;
6315 if (copy_acls)
6317 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6318 if (acl == NULL && acl_errno_valid (errno))
6319 return -2;
6321 if (w32_unicode_filenames)
6323 filename_to_utf16 (from, from_w);
6324 filename_to_utf16 (to, to_w);
6325 copy_result = CopyFileW (from_w, to_w, FALSE);
6327 else
6329 filename_to_ansi (from, from_a);
6330 filename_to_ansi (to, to_a);
6331 copy_result = CopyFileA (from_a, to_a, FALSE);
6333 if (!copy_result)
6335 /* CopyFile doesn't set errno when it fails. By far the most
6336 "popular" reason is that the target is read-only. */
6337 DWORD err = GetLastError ();
6339 switch (err)
6341 case ERROR_FILE_NOT_FOUND:
6342 errno = ENOENT;
6343 break;
6344 case ERROR_ACCESS_DENIED:
6345 errno = EACCES;
6346 break;
6347 case ERROR_ENCRYPTION_FAILED:
6348 errno = EIO;
6349 break;
6350 default:
6351 errno = EPERM;
6352 break;
6355 if (acl)
6356 acl_free (acl);
6357 return -1;
6359 /* CopyFile retains the timestamp by default. However, see
6360 "Community Additions" for CopyFile: it sounds like that is not
6361 entirely true. Testing on Windows XP confirms that modified time
6362 is copied, but creation and last-access times are not.
6363 FIXME? */
6364 else if (!keep_time)
6366 struct timespec now;
6367 DWORD attributes;
6369 if (w32_unicode_filenames)
6371 /* Ensure file is writable while its times are set. */
6372 attributes = GetFileAttributesW (to_w);
6373 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6374 now = current_timespec ();
6375 if (set_file_times (-1, to, now, now))
6377 /* Restore original attributes. */
6378 SetFileAttributesW (to_w, attributes);
6379 if (acl)
6380 acl_free (acl);
6381 return -3;
6383 /* Restore original attributes. */
6384 SetFileAttributesW (to_w, attributes);
6386 else
6388 attributes = GetFileAttributesA (to_a);
6389 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6390 now = current_timespec ();
6391 if (set_file_times (-1, to, now, now))
6393 SetFileAttributesA (to_a, attributes);
6394 if (acl)
6395 acl_free (acl);
6396 return -3;
6398 SetFileAttributesA (to_a, attributes);
6401 if (acl != NULL)
6403 bool fail =
6404 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6405 acl_free (acl);
6406 if (fail && acl_errno_valid (errno))
6407 return -4;
6410 return 0;
6414 /* Support for browsing other processes and their attributes. See
6415 process.c for the Lisp bindings. */
6417 /* Helper wrapper functions. */
6419 static HANDLE WINAPI
6420 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6422 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6424 if (g_b_init_create_toolhelp32_snapshot == 0)
6426 g_b_init_create_toolhelp32_snapshot = 1;
6427 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6428 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6429 "CreateToolhelp32Snapshot");
6431 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6433 return INVALID_HANDLE_VALUE;
6435 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6438 static BOOL WINAPI
6439 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6441 static Process32First_Proc s_pfn_Process32_First = NULL;
6443 if (g_b_init_process32_first == 0)
6445 g_b_init_process32_first = 1;
6446 s_pfn_Process32_First = (Process32First_Proc)
6447 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6448 "Process32First");
6450 if (s_pfn_Process32_First == NULL)
6452 return FALSE;
6454 return (s_pfn_Process32_First (hSnapshot, lppe));
6457 static BOOL WINAPI
6458 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6460 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6462 if (g_b_init_process32_next == 0)
6464 g_b_init_process32_next = 1;
6465 s_pfn_Process32_Next = (Process32Next_Proc)
6466 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6467 "Process32Next");
6469 if (s_pfn_Process32_Next == NULL)
6471 return FALSE;
6473 return (s_pfn_Process32_Next (hSnapshot, lppe));
6476 static BOOL WINAPI
6477 open_thread_token (HANDLE ThreadHandle,
6478 DWORD DesiredAccess,
6479 BOOL OpenAsSelf,
6480 PHANDLE TokenHandle)
6482 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6483 HMODULE hm_advapi32 = NULL;
6484 if (is_windows_9x () == TRUE)
6486 SetLastError (ERROR_NOT_SUPPORTED);
6487 return FALSE;
6489 if (g_b_init_open_thread_token == 0)
6491 g_b_init_open_thread_token = 1;
6492 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6493 s_pfn_Open_Thread_Token =
6494 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6496 if (s_pfn_Open_Thread_Token == NULL)
6498 SetLastError (ERROR_NOT_SUPPORTED);
6499 return FALSE;
6501 return (
6502 s_pfn_Open_Thread_Token (
6503 ThreadHandle,
6504 DesiredAccess,
6505 OpenAsSelf,
6506 TokenHandle)
6510 static BOOL WINAPI
6511 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6513 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6514 HMODULE hm_advapi32 = NULL;
6515 if (is_windows_9x () == TRUE)
6517 return FALSE;
6519 if (g_b_init_impersonate_self == 0)
6521 g_b_init_impersonate_self = 1;
6522 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6523 s_pfn_Impersonate_Self =
6524 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6526 if (s_pfn_Impersonate_Self == NULL)
6528 return FALSE;
6530 return s_pfn_Impersonate_Self (ImpersonationLevel);
6533 static BOOL WINAPI
6534 revert_to_self (void)
6536 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6537 HMODULE hm_advapi32 = NULL;
6538 if (is_windows_9x () == TRUE)
6540 return FALSE;
6542 if (g_b_init_revert_to_self == 0)
6544 g_b_init_revert_to_self = 1;
6545 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6546 s_pfn_Revert_To_Self =
6547 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6549 if (s_pfn_Revert_To_Self == NULL)
6551 return FALSE;
6553 return s_pfn_Revert_To_Self ();
6556 static BOOL WINAPI
6557 get_process_memory_info (HANDLE h_proc,
6558 PPROCESS_MEMORY_COUNTERS mem_counters,
6559 DWORD bufsize)
6561 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6562 HMODULE hm_psapi = NULL;
6563 if (is_windows_9x () == TRUE)
6565 return FALSE;
6567 if (g_b_init_get_process_memory_info == 0)
6569 g_b_init_get_process_memory_info = 1;
6570 hm_psapi = LoadLibrary ("Psapi.dll");
6571 if (hm_psapi)
6572 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6573 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6575 if (s_pfn_Get_Process_Memory_Info == NULL)
6577 return FALSE;
6579 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6582 static BOOL WINAPI
6583 get_process_working_set_size (HANDLE h_proc,
6584 PSIZE_T minrss,
6585 PSIZE_T maxrss)
6587 static GetProcessWorkingSetSize_Proc
6588 s_pfn_Get_Process_Working_Set_Size = NULL;
6590 if (is_windows_9x () == TRUE)
6592 return FALSE;
6594 if (g_b_init_get_process_working_set_size == 0)
6596 g_b_init_get_process_working_set_size = 1;
6597 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6598 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6599 "GetProcessWorkingSetSize");
6601 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6603 return FALSE;
6605 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6608 static BOOL WINAPI
6609 global_memory_status (MEMORYSTATUS *buf)
6611 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6613 if (is_windows_9x () == TRUE)
6615 return FALSE;
6617 if (g_b_init_global_memory_status == 0)
6619 g_b_init_global_memory_status = 1;
6620 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6621 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6622 "GlobalMemoryStatus");
6624 if (s_pfn_Global_Memory_Status == NULL)
6626 return FALSE;
6628 return s_pfn_Global_Memory_Status (buf);
6631 static BOOL WINAPI
6632 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6634 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6636 if (is_windows_9x () == TRUE)
6638 return FALSE;
6640 if (g_b_init_global_memory_status_ex == 0)
6642 g_b_init_global_memory_status_ex = 1;
6643 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6644 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6645 "GlobalMemoryStatusEx");
6647 if (s_pfn_Global_Memory_Status_Ex == NULL)
6649 return FALSE;
6651 return s_pfn_Global_Memory_Status_Ex (buf);
6654 Lisp_Object
6655 list_system_processes (void)
6657 Lisp_Object proclist = Qnil;
6658 HANDLE h_snapshot;
6660 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6662 if (h_snapshot != INVALID_HANDLE_VALUE)
6664 PROCESSENTRY32 proc_entry;
6665 DWORD proc_id;
6666 BOOL res;
6668 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6669 for (res = process32_first (h_snapshot, &proc_entry); res;
6670 res = process32_next (h_snapshot, &proc_entry))
6672 proc_id = proc_entry.th32ProcessID;
6673 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6676 CloseHandle (h_snapshot);
6677 proclist = Fnreverse (proclist);
6680 return proclist;
6683 static int
6684 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6686 TOKEN_PRIVILEGES priv;
6687 DWORD priv_size = sizeof (priv);
6688 DWORD opriv_size = sizeof (*old_priv);
6689 HANDLE h_token = NULL;
6690 HANDLE h_thread = GetCurrentThread ();
6691 int ret_val = 0;
6692 BOOL res;
6694 res = open_thread_token (h_thread,
6695 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6696 FALSE, &h_token);
6697 if (!res && GetLastError () == ERROR_NO_TOKEN)
6699 if (impersonate_self (SecurityImpersonation))
6700 res = open_thread_token (h_thread,
6701 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6702 FALSE, &h_token);
6704 if (res)
6706 priv.PrivilegeCount = 1;
6707 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6708 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6709 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6710 old_priv, &opriv_size)
6711 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6712 ret_val = 1;
6714 if (h_token)
6715 CloseHandle (h_token);
6717 return ret_val;
6720 static int
6721 restore_privilege (TOKEN_PRIVILEGES *priv)
6723 DWORD priv_size = sizeof (*priv);
6724 HANDLE h_token = NULL;
6725 int ret_val = 0;
6727 if (open_thread_token (GetCurrentThread (),
6728 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6729 FALSE, &h_token))
6731 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6732 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6733 ret_val = 1;
6735 if (h_token)
6736 CloseHandle (h_token);
6738 return ret_val;
6741 static Lisp_Object
6742 ltime (ULONGLONG time_100ns)
6744 ULONGLONG time_sec = time_100ns / 10000000;
6745 int subsec = time_100ns % 10000000;
6746 return list4i (time_sec >> 16, time_sec & 0xffff,
6747 subsec / 10, subsec % 10 * 100000);
6750 #define U64_TO_LISP_TIME(time) ltime (time)
6752 static int
6753 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6754 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6755 double *pcpu)
6757 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6758 ULONGLONG tem1, tem2, tem3, tem;
6760 if (!h_proc
6761 || !get_process_times_fn
6762 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6763 &ft_kernel, &ft_user))
6764 return 0;
6766 GetSystemTimeAsFileTime (&ft_current);
6768 FILETIME_TO_U64 (tem1, ft_kernel);
6769 *stime = U64_TO_LISP_TIME (tem1);
6771 FILETIME_TO_U64 (tem2, ft_user);
6772 *utime = U64_TO_LISP_TIME (tem2);
6774 tem3 = tem1 + tem2;
6775 *ttime = U64_TO_LISP_TIME (tem3);
6777 FILETIME_TO_U64 (tem, ft_creation);
6778 /* Process no 4 (System) returns zero creation time. */
6779 if (tem)
6780 tem -= utc_base;
6781 *ctime = U64_TO_LISP_TIME (tem);
6783 if (tem)
6785 FILETIME_TO_U64 (tem3, ft_current);
6786 tem = (tem3 - utc_base) - tem;
6788 *etime = U64_TO_LISP_TIME (tem);
6790 if (tem)
6792 *pcpu = 100.0 * (tem1 + tem2) / tem;
6793 if (*pcpu > 100)
6794 *pcpu = 100.0;
6796 else
6797 *pcpu = 0;
6799 return 1;
6802 Lisp_Object
6803 system_process_attributes (Lisp_Object pid)
6805 Lisp_Object attrs = Qnil;
6806 Lisp_Object cmd_str, decoded_cmd, tem;
6807 HANDLE h_snapshot, h_proc;
6808 DWORD proc_id;
6809 int found_proc = 0;
6810 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6811 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6812 DWORD glength = sizeof (gname);
6813 HANDLE token = NULL;
6814 SID_NAME_USE user_type;
6815 unsigned char *buf = NULL;
6816 DWORD blen = 0;
6817 TOKEN_USER user_token;
6818 TOKEN_PRIMARY_GROUP group_token;
6819 unsigned euid;
6820 unsigned egid;
6821 PROCESS_MEMORY_COUNTERS mem;
6822 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6823 SIZE_T minrss, maxrss;
6824 MEMORYSTATUS memst;
6825 MEMORY_STATUS_EX memstex;
6826 double totphys = 0.0;
6827 Lisp_Object ctime, stime, utime, etime, ttime;
6828 double pcpu;
6829 BOOL result = FALSE;
6831 CHECK_NUMBER_OR_FLOAT (pid);
6832 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6834 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6836 if (h_snapshot != INVALID_HANDLE_VALUE)
6838 PROCESSENTRY32 pe;
6839 BOOL res;
6841 pe.dwSize = sizeof (PROCESSENTRY32);
6842 for (res = process32_first (h_snapshot, &pe); res;
6843 res = process32_next (h_snapshot, &pe))
6845 if (proc_id == pe.th32ProcessID)
6847 if (proc_id == 0)
6848 decoded_cmd = build_string ("Idle");
6849 else
6851 /* Decode the command name from locale-specific
6852 encoding. */
6853 cmd_str = build_unibyte_string (pe.szExeFile);
6855 decoded_cmd =
6856 code_convert_string_norecord (cmd_str,
6857 Vlocale_coding_system, 0);
6859 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6860 attrs = Fcons (Fcons (Qppid,
6861 make_fixnum_or_float (pe.th32ParentProcessID)),
6862 attrs);
6863 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6864 attrs);
6865 attrs = Fcons (Fcons (Qthcount,
6866 make_fixnum_or_float (pe.cntThreads)),
6867 attrs);
6868 found_proc = 1;
6869 break;
6873 CloseHandle (h_snapshot);
6876 if (!found_proc)
6877 return Qnil;
6879 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6880 FALSE, proc_id);
6881 /* If we were denied a handle to the process, try again after
6882 enabling the SeDebugPrivilege in our process. */
6883 if (!h_proc)
6885 TOKEN_PRIVILEGES priv_current;
6887 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6889 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6890 FALSE, proc_id);
6891 restore_privilege (&priv_current);
6892 revert_to_self ();
6895 if (h_proc)
6897 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6898 if (result)
6900 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6901 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6903 buf = xmalloc (blen);
6904 result = get_token_information (token, TokenUser,
6905 (LPVOID)buf, blen, &needed);
6906 if (result)
6908 memcpy (&user_token, buf, sizeof (user_token));
6909 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6911 euid = get_rid (user_token.User.Sid);
6912 result = lookup_account_sid (NULL, user_token.User.Sid,
6913 uname, &ulength,
6914 domain, &dlength,
6915 &user_type);
6916 if (result)
6917 w32_add_to_cache (user_token.User.Sid, euid, uname);
6918 else
6920 strcpy (uname, "unknown");
6921 result = TRUE;
6924 ulength = strlen (uname);
6928 if (result)
6930 /* Determine a reasonable euid and gid values. */
6931 if (xstrcasecmp ("administrator", uname) == 0)
6933 euid = 500; /* well-known Administrator uid */
6934 egid = 513; /* well-known None gid */
6936 else
6938 /* Get group id and name. */
6939 result = get_token_information (token, TokenPrimaryGroup,
6940 (LPVOID)buf, blen, &needed);
6941 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6943 buf = xrealloc (buf, blen = needed);
6944 result = get_token_information (token, TokenPrimaryGroup,
6945 (LPVOID)buf, blen, &needed);
6947 if (result)
6949 memcpy (&group_token, buf, sizeof (group_token));
6950 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6952 egid = get_rid (group_token.PrimaryGroup);
6953 dlength = sizeof (domain);
6954 result =
6955 lookup_account_sid (NULL, group_token.PrimaryGroup,
6956 gname, &glength, NULL, &dlength,
6957 &user_type);
6958 if (result)
6959 w32_add_to_cache (group_token.PrimaryGroup,
6960 egid, gname);
6961 else
6963 strcpy (gname, "None");
6964 result = TRUE;
6967 glength = strlen (gname);
6971 xfree (buf);
6973 if (!result)
6975 if (!is_windows_9x ())
6977 /* We couldn't open the process token, presumably because of
6978 insufficient access rights. Assume this process is run
6979 by the system. */
6980 strcpy (uname, "SYSTEM");
6981 strcpy (gname, "None");
6982 euid = 18; /* SYSTEM */
6983 egid = 513; /* None */
6984 glength = strlen (gname);
6985 ulength = strlen (uname);
6987 /* If we are running under Windows 9X, where security calls are
6988 not supported, we assume all processes are run by the current
6989 user. */
6990 else if (GetUserName (uname, &ulength))
6992 if (xstrcasecmp ("administrator", uname) == 0)
6993 euid = 0;
6994 else
6995 euid = 123;
6996 egid = euid;
6997 strcpy (gname, "None");
6998 glength = strlen (gname);
6999 ulength = strlen (uname);
7001 else
7003 euid = 123;
7004 egid = 123;
7005 strcpy (uname, "administrator");
7006 ulength = strlen (uname);
7007 strcpy (gname, "None");
7008 glength = strlen (gname);
7010 if (token)
7011 CloseHandle (token);
7014 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7015 tem = make_unibyte_string (uname, ulength);
7016 attrs = Fcons (Fcons (Quser,
7017 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7018 attrs);
7019 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7020 tem = make_unibyte_string (gname, glength);
7021 attrs = Fcons (Fcons (Qgroup,
7022 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7023 attrs);
7025 if (global_memory_status_ex (&memstex))
7026 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7027 totphys = memstex.ullTotalPhys / 1024.0;
7028 #else
7029 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7030 double, so we need to do this for it... */
7032 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7033 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7034 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7036 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7038 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7039 else if (global_memory_status (&memst))
7040 totphys = memst.dwTotalPhys / 1024.0;
7042 if (h_proc
7043 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7044 sizeof (mem_ex)))
7046 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7048 attrs = Fcons (Fcons (Qmajflt,
7049 make_fixnum_or_float (mem_ex.PageFaultCount)),
7050 attrs);
7051 attrs = Fcons (Fcons (Qvsize,
7052 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7053 attrs);
7054 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7055 if (totphys)
7056 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7058 else if (h_proc
7059 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7061 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7063 attrs = Fcons (Fcons (Qmajflt,
7064 make_fixnum_or_float (mem.PageFaultCount)),
7065 attrs);
7066 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7067 if (totphys)
7068 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7070 else if (h_proc
7071 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7073 DWORD rss = maxrss / 1024;
7075 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7076 if (totphys)
7077 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7080 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7082 attrs = Fcons (Fcons (Qutime, utime), attrs);
7083 attrs = Fcons (Fcons (Qstime, stime), attrs);
7084 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7085 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7086 attrs = Fcons (Fcons (Qetime, etime), attrs);
7087 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7090 /* FIXME: Retrieve command line by walking the PEB of the process. */
7092 if (h_proc)
7093 CloseHandle (h_proc);
7094 return attrs;
7098 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7099 unsigned long long *totalswap, unsigned long long *freeswap)
7101 MEMORYSTATUS memst;
7102 MEMORY_STATUS_EX memstex;
7104 /* Use GlobalMemoryStatusEx if available, as it can report more than
7105 2GB of memory. */
7106 if (global_memory_status_ex (&memstex))
7108 *totalram = memstex.ullTotalPhys;
7109 *freeram = memstex.ullAvailPhys;
7110 *totalswap = memstex.ullTotalPageFile;
7111 *freeswap = memstex.ullAvailPageFile;
7112 return 0;
7114 else if (global_memory_status (&memst))
7116 *totalram = memst.dwTotalPhys;
7117 *freeram = memst.dwAvailPhys;
7118 *totalswap = memst.dwTotalPageFile;
7119 *freeswap = memst.dwAvailPageFile;
7120 return 0;
7122 else
7123 return -1;
7127 /* Wrappers for winsock functions to map between our file descriptors
7128 and winsock's handles; also set h_errno for convenience.
7130 To allow Emacs to run on systems which don't have winsock support
7131 installed, we dynamically link to winsock on startup if present, and
7132 otherwise provide the minimum necessary functionality
7133 (eg. gethostname). */
7135 /* function pointers for relevant socket functions */
7136 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7137 void (PASCAL *pfn_WSASetLastError) (int iError);
7138 int (PASCAL *pfn_WSAGetLastError) (void);
7139 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7140 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7141 WSANETWORKEVENTS *NetworkEvents);
7143 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7144 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7145 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7146 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7147 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7148 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7149 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7150 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7151 int (PASCAL *pfn_closesocket) (SOCKET s);
7152 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7153 int (PASCAL *pfn_WSACleanup) (void);
7155 u_short (PASCAL *pfn_htons) (u_short hostshort);
7156 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7157 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7158 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7159 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7160 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7161 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7162 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7163 const char * optval, int optlen);
7164 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7165 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7166 int * namelen);
7167 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7168 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7169 struct sockaddr * from, int * fromlen);
7170 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7171 const struct sockaddr * to, int tolen);
7173 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7174 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7175 #ifndef HANDLE_FLAG_INHERIT
7176 #define HANDLE_FLAG_INHERIT 1
7177 #endif
7179 HANDLE winsock_lib;
7180 static int winsock_inuse;
7182 BOOL
7183 term_winsock (void)
7185 if (winsock_lib != NULL && winsock_inuse == 0)
7187 release_listen_threads ();
7188 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7189 after WSAStartup returns successfully, but it seems reasonable
7190 to allow unloading winsock anyway in that case. */
7191 if (pfn_WSACleanup () == 0 ||
7192 pfn_WSAGetLastError () == WSAENETDOWN)
7194 if (FreeLibrary (winsock_lib))
7195 winsock_lib = NULL;
7196 return TRUE;
7199 return FALSE;
7202 BOOL
7203 init_winsock (int load_now)
7205 WSADATA winsockData;
7207 if (winsock_lib != NULL)
7208 return TRUE;
7210 pfn_SetHandleInformation
7211 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7212 "SetHandleInformation");
7214 winsock_lib = LoadLibrary ("Ws2_32.dll");
7216 if (winsock_lib != NULL)
7218 /* dynamically link to socket functions */
7220 #define LOAD_PROC(fn) \
7221 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7222 goto fail;
7224 LOAD_PROC (WSAStartup);
7225 LOAD_PROC (WSASetLastError);
7226 LOAD_PROC (WSAGetLastError);
7227 LOAD_PROC (WSAEventSelect);
7228 LOAD_PROC (WSAEnumNetworkEvents);
7229 LOAD_PROC (WSACreateEvent);
7230 LOAD_PROC (WSACloseEvent);
7231 LOAD_PROC (socket);
7232 LOAD_PROC (bind);
7233 LOAD_PROC (connect);
7234 LOAD_PROC (ioctlsocket);
7235 LOAD_PROC (recv);
7236 LOAD_PROC (send);
7237 LOAD_PROC (closesocket);
7238 LOAD_PROC (shutdown);
7239 LOAD_PROC (htons);
7240 LOAD_PROC (ntohs);
7241 LOAD_PROC (inet_addr);
7242 LOAD_PROC (gethostname);
7243 LOAD_PROC (gethostbyname);
7244 LOAD_PROC (getservbyname);
7245 LOAD_PROC (getpeername);
7246 LOAD_PROC (WSACleanup);
7247 LOAD_PROC (setsockopt);
7248 LOAD_PROC (listen);
7249 LOAD_PROC (getsockname);
7250 LOAD_PROC (accept);
7251 LOAD_PROC (recvfrom);
7252 LOAD_PROC (sendto);
7253 #undef LOAD_PROC
7255 /* specify version 1.1 of winsock */
7256 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7258 if (winsockData.wVersion != 0x101)
7259 goto fail;
7261 if (!load_now)
7263 /* Report that winsock exists and is usable, but leave
7264 socket functions disabled. I am assuming that calling
7265 WSAStartup does not require any network interaction,
7266 and in particular does not cause or require a dial-up
7267 connection to be established. */
7269 pfn_WSACleanup ();
7270 FreeLibrary (winsock_lib);
7271 winsock_lib = NULL;
7273 winsock_inuse = 0;
7274 return TRUE;
7277 fail:
7278 FreeLibrary (winsock_lib);
7279 winsock_lib = NULL;
7282 return FALSE;
7286 int h_errno = 0;
7288 /* Function to map winsock error codes to errno codes for those errno
7289 code defined in errno.h (errno values not defined by errno.h are
7290 already in nt/inc/sys/socket.h). */
7291 static void
7292 set_errno (void)
7294 int wsa_err;
7296 h_errno = 0;
7297 if (winsock_lib == NULL)
7298 wsa_err = EINVAL;
7299 else
7300 wsa_err = pfn_WSAGetLastError ();
7302 switch (wsa_err)
7304 case WSAEACCES: errno = EACCES; break;
7305 case WSAEBADF: errno = EBADF; break;
7306 case WSAEFAULT: errno = EFAULT; break;
7307 case WSAEINTR: errno = EINTR; break;
7308 case WSAEINVAL: errno = EINVAL; break;
7309 case WSAEMFILE: errno = EMFILE; break;
7310 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7311 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7312 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7313 case WSAENOTCONN: errno = ENOTCONN; break;
7314 default: errno = wsa_err; break;
7318 static void
7319 check_errno (void)
7321 h_errno = 0;
7322 if (winsock_lib != NULL)
7323 pfn_WSASetLastError (0);
7326 /* Extend strerror to handle the winsock-specific error codes. */
7327 struct {
7328 int errnum;
7329 char * msg;
7330 } _wsa_errlist[] = {
7331 {WSAEINTR , "Interrupted function call"},
7332 {WSAEBADF , "Bad file descriptor"},
7333 {WSAEACCES , "Permission denied"},
7334 {WSAEFAULT , "Bad address"},
7335 {WSAEINVAL , "Invalid argument"},
7336 {WSAEMFILE , "Too many open files"},
7338 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7339 {WSAEINPROGRESS , "Operation now in progress"},
7340 {WSAEALREADY , "Operation already in progress"},
7341 {WSAENOTSOCK , "Socket operation on non-socket"},
7342 {WSAEDESTADDRREQ , "Destination address required"},
7343 {WSAEMSGSIZE , "Message too long"},
7344 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7345 {WSAENOPROTOOPT , "Bad protocol option"},
7346 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7347 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7348 {WSAEOPNOTSUPP , "Operation not supported"},
7349 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7350 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7351 {WSAEADDRINUSE , "Address already in use"},
7352 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7353 {WSAENETDOWN , "Network is down"},
7354 {WSAENETUNREACH , "Network is unreachable"},
7355 {WSAENETRESET , "Network dropped connection on reset"},
7356 {WSAECONNABORTED , "Software caused connection abort"},
7357 {WSAECONNRESET , "Connection reset by peer"},
7358 {WSAENOBUFS , "No buffer space available"},
7359 {WSAEISCONN , "Socket is already connected"},
7360 {WSAENOTCONN , "Socket is not connected"},
7361 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7362 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7363 {WSAETIMEDOUT , "Connection timed out"},
7364 {WSAECONNREFUSED , "Connection refused"},
7365 {WSAELOOP , "Network loop"}, /* not sure */
7366 {WSAENAMETOOLONG , "Name is too long"},
7367 {WSAEHOSTDOWN , "Host is down"},
7368 {WSAEHOSTUNREACH , "No route to host"},
7369 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7370 {WSAEPROCLIM , "Too many processes"},
7371 {WSAEUSERS , "Too many users"}, /* not sure */
7372 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7373 {WSAESTALE , "Data is stale"}, /* not sure */
7374 {WSAEREMOTE , "Remote error"}, /* not sure */
7376 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7377 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7378 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7379 {WSAEDISCON , "Graceful shutdown in progress"},
7380 #ifdef WSAENOMORE
7381 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7382 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7383 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7384 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7385 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7386 {WSASYSCALLFAILURE , "System call failure"},
7387 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7388 {WSATYPE_NOT_FOUND , "Class type not found"},
7389 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7390 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7391 {WSAEREFUSED , "Operation refused"}, /* not sure */
7392 #endif
7394 {WSAHOST_NOT_FOUND , "Host not found"},
7395 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7396 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7397 {WSANO_DATA , "Valid name, no data record of requested type"},
7399 {-1, NULL}
7402 char *
7403 sys_strerror (int error_no)
7405 int i;
7406 static char unknown_msg[40];
7408 if (error_no >= 0 && error_no < sys_nerr)
7409 return sys_errlist[error_no];
7411 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7412 if (_wsa_errlist[i].errnum == error_no)
7413 return _wsa_errlist[i].msg;
7415 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7416 return unknown_msg;
7419 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7420 but I believe the method of keeping the socket handle separate (and
7421 insuring it is not inheritable) is the correct one. */
7423 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7425 static int socket_to_fd (SOCKET s);
7428 sys_socket (int af, int type, int protocol)
7430 SOCKET s;
7432 if (winsock_lib == NULL)
7434 errno = ENETDOWN;
7435 return -1;
7438 check_errno ();
7440 /* call the real socket function */
7441 s = pfn_socket (af, type, protocol);
7443 if (s != INVALID_SOCKET)
7444 return socket_to_fd (s);
7446 set_errno ();
7447 return -1;
7450 /* Convert a SOCKET to a file descriptor. */
7451 static int
7452 socket_to_fd (SOCKET s)
7454 int fd;
7455 child_process * cp;
7457 /* Although under NT 3.5 _open_osfhandle will accept a socket
7458 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7459 that does not work under NT 3.1. However, we can get the same
7460 effect by using a backdoor function to replace an existing
7461 descriptor handle with the one we want. */
7463 /* allocate a file descriptor (with appropriate flags) */
7464 fd = _open ("NUL:", _O_RDWR);
7465 if (fd >= 0)
7467 /* Make a non-inheritable copy of the socket handle. Note
7468 that it is possible that sockets aren't actually kernel
7469 handles, which appears to be the case on Windows 9x when
7470 the MS Proxy winsock client is installed. */
7472 /* Apparently there is a bug in NT 3.51 with some service
7473 packs, which prevents using DuplicateHandle to make a
7474 socket handle non-inheritable (causes WSACleanup to
7475 hang). The work-around is to use SetHandleInformation
7476 instead if it is available and implemented. */
7477 if (pfn_SetHandleInformation)
7479 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7481 else
7483 HANDLE parent = GetCurrentProcess ();
7484 HANDLE new_s = INVALID_HANDLE_VALUE;
7486 if (DuplicateHandle (parent,
7487 (HANDLE) s,
7488 parent,
7489 &new_s,
7491 FALSE,
7492 DUPLICATE_SAME_ACCESS))
7494 /* It is possible that DuplicateHandle succeeds even
7495 though the socket wasn't really a kernel handle,
7496 because a real handle has the same value. So
7497 test whether the new handle really is a socket. */
7498 long nonblocking = 0;
7499 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7501 pfn_closesocket (s);
7502 s = (SOCKET) new_s;
7504 else
7506 CloseHandle (new_s);
7511 eassert (fd < MAXDESC);
7512 fd_info[fd].hnd = (HANDLE) s;
7514 /* set our own internal flags */
7515 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7517 cp = new_child ();
7518 if (cp)
7520 cp->fd = fd;
7521 cp->status = STATUS_READ_ACKNOWLEDGED;
7523 /* attach child_process to fd_info */
7524 if (fd_info[ fd ].cp != NULL)
7526 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7527 emacs_abort ();
7530 fd_info[ fd ].cp = cp;
7532 /* success! */
7533 winsock_inuse++; /* count open sockets */
7534 return fd;
7537 /* clean up */
7538 _close (fd);
7540 else
7541 pfn_closesocket (s);
7542 errno = EMFILE;
7543 return -1;
7547 sys_bind (int s, const struct sockaddr * addr, int namelen)
7549 if (winsock_lib == NULL)
7551 errno = ENOTSOCK;
7552 return SOCKET_ERROR;
7555 check_errno ();
7556 if (fd_info[s].flags & FILE_SOCKET)
7558 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7559 if (rc == SOCKET_ERROR)
7560 set_errno ();
7561 return rc;
7563 errno = ENOTSOCK;
7564 return SOCKET_ERROR;
7568 sys_connect (int s, const struct sockaddr * name, int namelen)
7570 if (winsock_lib == NULL)
7572 errno = ENOTSOCK;
7573 return SOCKET_ERROR;
7576 check_errno ();
7577 if (fd_info[s].flags & FILE_SOCKET)
7579 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7580 if (rc == SOCKET_ERROR)
7582 set_errno ();
7583 /* If this is a non-blocking 'connect', set the bit in flags
7584 that will tell reader_thread to wait for connection
7585 before trying to read. */
7586 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7588 errno = EINPROGRESS; /* that's what process.c expects */
7589 fd_info[s].flags |= FILE_CONNECT;
7592 return rc;
7594 errno = ENOTSOCK;
7595 return SOCKET_ERROR;
7598 u_short
7599 sys_htons (u_short hostshort)
7601 return (winsock_lib != NULL) ?
7602 pfn_htons (hostshort) : hostshort;
7605 u_short
7606 sys_ntohs (u_short netshort)
7608 return (winsock_lib != NULL) ?
7609 pfn_ntohs (netshort) : netshort;
7612 unsigned long
7613 sys_inet_addr (const char * cp)
7615 return (winsock_lib != NULL) ?
7616 pfn_inet_addr (cp) : INADDR_NONE;
7620 sys_gethostname (char * name, int namelen)
7622 if (winsock_lib != NULL)
7624 int retval;
7626 check_errno ();
7627 retval = pfn_gethostname (name, namelen);
7628 if (retval == SOCKET_ERROR)
7629 set_errno ();
7630 return retval;
7633 if (namelen > MAX_COMPUTERNAME_LENGTH)
7634 return !GetComputerName (name, (DWORD *)&namelen);
7636 errno = EFAULT;
7637 return SOCKET_ERROR;
7640 struct hostent *
7641 sys_gethostbyname (const char * name)
7643 struct hostent * host;
7644 int h_err = h_errno;
7646 if (winsock_lib == NULL)
7648 h_errno = NO_RECOVERY;
7649 errno = ENETDOWN;
7650 return NULL;
7653 check_errno ();
7654 host = pfn_gethostbyname (name);
7655 if (!host)
7657 set_errno ();
7658 h_errno = errno;
7660 else
7661 h_errno = h_err;
7662 return host;
7665 struct servent *
7666 sys_getservbyname (const char * name, const char * proto)
7668 struct servent * serv;
7670 if (winsock_lib == NULL)
7672 errno = ENETDOWN;
7673 return NULL;
7676 check_errno ();
7677 serv = pfn_getservbyname (name, proto);
7678 if (!serv)
7679 set_errno ();
7680 return serv;
7684 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7686 if (winsock_lib == NULL)
7688 errno = ENETDOWN;
7689 return SOCKET_ERROR;
7692 check_errno ();
7693 if (fd_info[s].flags & FILE_SOCKET)
7695 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7696 if (rc == SOCKET_ERROR)
7697 set_errno ();
7698 return rc;
7700 errno = ENOTSOCK;
7701 return SOCKET_ERROR;
7705 sys_shutdown (int s, int how)
7707 if (winsock_lib == NULL)
7709 errno = ENETDOWN;
7710 return SOCKET_ERROR;
7713 check_errno ();
7714 if (fd_info[s].flags & FILE_SOCKET)
7716 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7717 if (rc == SOCKET_ERROR)
7718 set_errno ();
7719 return rc;
7721 errno = ENOTSOCK;
7722 return SOCKET_ERROR;
7726 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7728 if (winsock_lib == NULL)
7730 errno = ENETDOWN;
7731 return SOCKET_ERROR;
7734 check_errno ();
7735 if (fd_info[s].flags & FILE_SOCKET)
7737 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7738 (const char *)optval, optlen);
7739 if (rc == SOCKET_ERROR)
7740 set_errno ();
7741 return rc;
7743 errno = ENOTSOCK;
7744 return SOCKET_ERROR;
7748 sys_listen (int s, int backlog)
7750 if (winsock_lib == NULL)
7752 errno = ENETDOWN;
7753 return SOCKET_ERROR;
7756 check_errno ();
7757 if (fd_info[s].flags & FILE_SOCKET)
7759 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7760 if (rc == SOCKET_ERROR)
7761 set_errno ();
7762 else
7763 fd_info[s].flags |= FILE_LISTEN;
7764 return rc;
7766 errno = ENOTSOCK;
7767 return SOCKET_ERROR;
7771 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7773 if (winsock_lib == NULL)
7775 errno = ENETDOWN;
7776 return SOCKET_ERROR;
7779 check_errno ();
7780 if (fd_info[s].flags & FILE_SOCKET)
7782 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7783 if (rc == SOCKET_ERROR)
7784 set_errno ();
7785 return rc;
7787 errno = ENOTSOCK;
7788 return SOCKET_ERROR;
7792 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7794 if (winsock_lib == NULL)
7796 errno = ENETDOWN;
7797 return -1;
7800 check_errno ();
7801 if (fd_info[s].flags & FILE_LISTEN)
7803 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7804 int fd = -1;
7805 if (t == INVALID_SOCKET)
7806 set_errno ();
7807 else
7808 fd = socket_to_fd (t);
7810 if (fd >= 0)
7812 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7813 ResetEvent (fd_info[s].cp->char_avail);
7815 return fd;
7817 errno = ENOTSOCK;
7818 return -1;
7822 sys_recvfrom (int s, char * buf, int len, int flags,
7823 struct sockaddr * from, int * fromlen)
7825 if (winsock_lib == NULL)
7827 errno = ENETDOWN;
7828 return SOCKET_ERROR;
7831 check_errno ();
7832 if (fd_info[s].flags & FILE_SOCKET)
7834 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7835 if (rc == SOCKET_ERROR)
7836 set_errno ();
7837 return rc;
7839 errno = ENOTSOCK;
7840 return SOCKET_ERROR;
7844 sys_sendto (int s, const char * buf, int len, int flags,
7845 const struct sockaddr * to, int tolen)
7847 if (winsock_lib == NULL)
7849 errno = ENETDOWN;
7850 return SOCKET_ERROR;
7853 check_errno ();
7854 if (fd_info[s].flags & FILE_SOCKET)
7856 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7857 if (rc == SOCKET_ERROR)
7858 set_errno ();
7859 return rc;
7861 errno = ENOTSOCK;
7862 return SOCKET_ERROR;
7865 /* Windows does not have an fcntl function. Provide an implementation
7866 good enough for Emacs. */
7868 fcntl (int s, int cmd, int options)
7870 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7871 invoked in a context where fd1 is closed and all descriptors less
7872 than fd1 are open, so sys_dup is an adequate implementation. */
7873 if (cmd == F_DUPFD_CLOEXEC)
7874 return sys_dup (s);
7876 check_errno ();
7877 if (fd_info[s].flags & FILE_SOCKET)
7879 if (winsock_lib == NULL)
7881 errno = ENETDOWN;
7882 return -1;
7885 if (cmd == F_SETFL && options == O_NONBLOCK)
7887 unsigned long nblock = 1;
7888 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7889 if (rc == SOCKET_ERROR)
7890 set_errno ();
7891 /* Keep track of the fact that we set this to non-blocking. */
7892 fd_info[s].flags |= FILE_NDELAY;
7893 return rc;
7895 else
7897 errno = EINVAL;
7898 return SOCKET_ERROR;
7901 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
7902 == (FILE_PIPE | FILE_WRITE))
7904 /* Force our writes to pipes be non-blocking. */
7905 if (cmd == F_SETFL && options == O_NONBLOCK)
7907 HANDLE h = (HANDLE)_get_osfhandle (s);
7908 DWORD pipe_mode = PIPE_NOWAIT;
7910 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
7912 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
7913 return SOCKET_ERROR;
7915 fd_info[s].flags |= FILE_NDELAY;
7916 return 0;
7918 else
7920 errno = EINVAL;
7921 return SOCKET_ERROR;
7924 errno = ENOTSOCK;
7925 return SOCKET_ERROR;
7929 /* Shadow main io functions: we need to handle pipes and sockets more
7930 intelligently. */
7933 sys_close (int fd)
7935 int rc;
7937 if (fd < 0)
7939 errno = EBADF;
7940 return -1;
7943 if (fd < MAXDESC && fd_info[fd].cp)
7945 child_process * cp = fd_info[fd].cp;
7947 fd_info[fd].cp = NULL;
7949 if (CHILD_ACTIVE (cp))
7951 /* if last descriptor to active child_process then cleanup */
7952 int i;
7953 for (i = 0; i < MAXDESC; i++)
7955 if (i == fd)
7956 continue;
7957 if (fd_info[i].cp == cp)
7958 break;
7960 if (i == MAXDESC)
7962 if (fd_info[fd].flags & FILE_SOCKET)
7964 if (winsock_lib == NULL) emacs_abort ();
7966 pfn_shutdown (SOCK_HANDLE (fd), 2);
7967 rc = pfn_closesocket (SOCK_HANDLE (fd));
7969 winsock_inuse--; /* count open sockets */
7971 /* If the process handle is NULL, it's either a socket
7972 or serial connection, or a subprocess that was
7973 already reaped by reap_subprocess, but whose
7974 resources were not yet freed, because its output was
7975 not fully read yet by the time it was reaped. (This
7976 usually happens with async subprocesses whose output
7977 is being read by Emacs.) Otherwise, this process was
7978 not reaped yet, so we set its FD to a negative value
7979 to make sure sys_select will eventually get to
7980 calling the SIGCHLD handler for it, which will then
7981 invoke waitpid and reap_subprocess. */
7982 if (cp->procinfo.hProcess == NULL)
7983 delete_child (cp);
7984 else
7985 cp->fd = -1;
7990 if (fd >= 0 && fd < MAXDESC)
7991 fd_info[fd].flags = 0;
7993 /* Note that sockets do not need special treatment here (at least on
7994 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7995 closesocket is equivalent to CloseHandle, which is to be expected
7996 because socket handles are fully fledged kernel handles. */
7997 rc = _close (fd);
7999 return rc;
8003 sys_dup (int fd)
8005 int new_fd;
8007 new_fd = _dup (fd);
8008 if (new_fd >= 0 && new_fd < MAXDESC)
8010 /* duplicate our internal info as well */
8011 fd_info[new_fd] = fd_info[fd];
8013 return new_fd;
8017 sys_dup2 (int src, int dst)
8019 int rc;
8021 if (dst < 0 || dst >= MAXDESC)
8023 errno = EBADF;
8024 return -1;
8027 /* make sure we close the destination first if it's a pipe or socket */
8028 if (src != dst && fd_info[dst].flags != 0)
8029 sys_close (dst);
8031 rc = _dup2 (src, dst);
8032 if (rc == 0)
8034 /* duplicate our internal info as well */
8035 fd_info[dst] = fd_info[src];
8037 return rc;
8041 pipe2 (int * phandles, int pipe2_flags)
8043 int rc;
8044 unsigned flags;
8046 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8048 /* make pipe handles non-inheritable; when we spawn a child, we
8049 replace the relevant handle with an inheritable one. Also put
8050 pipes into binary mode; we will do text mode translation ourselves
8051 if required. */
8052 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
8054 if (rc == 0)
8056 /* Protect against overflow, since Windows can open more handles than
8057 our fd_info array has room for. */
8058 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8060 _close (phandles[0]);
8061 _close (phandles[1]);
8062 errno = EMFILE;
8063 rc = -1;
8065 else
8067 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8068 fd_info[phandles[0]].flags = flags;
8070 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8071 fd_info[phandles[1]].flags = flags;
8075 return rc;
8078 /* Function to do blocking read of one byte, needed to implement
8079 select. It is only allowed on communication ports, sockets, or
8080 pipes. */
8082 _sys_read_ahead (int fd)
8084 child_process * cp;
8085 int rc;
8087 if (fd < 0 || fd >= MAXDESC)
8088 return STATUS_READ_ERROR;
8090 cp = fd_info[fd].cp;
8092 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8093 return STATUS_READ_ERROR;
8095 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8096 || (fd_info[fd].flags & FILE_READ) == 0)
8098 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8099 emacs_abort ();
8102 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8103 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8104 cp->status = STATUS_READ_IN_PROGRESS;
8106 if (fd_info[fd].flags & FILE_PIPE)
8108 rc = _read (fd, &cp->chr, sizeof (char));
8110 /* Give subprocess time to buffer some more output for us before
8111 reporting that input is available; we need this because Windows 95
8112 connects DOS programs to pipes by making the pipe appear to be
8113 the normal console stdout - as a result most DOS programs will
8114 write to stdout without buffering, ie. one character at a
8115 time. Even some W32 programs do this - "dir" in a command
8116 shell on NT is very slow if we don't do this. */
8117 if (rc > 0)
8119 int wait = w32_pipe_read_delay;
8121 if (wait > 0)
8122 Sleep (wait);
8123 else if (wait < 0)
8124 while (++wait <= 0)
8125 /* Yield remainder of our time slice, effectively giving a
8126 temporary priority boost to the child process. */
8127 Sleep (0);
8130 else if (fd_info[fd].flags & FILE_SERIAL)
8132 HANDLE hnd = fd_info[fd].hnd;
8133 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8134 COMMTIMEOUTS ct;
8136 /* Configure timeouts for blocking read. */
8137 if (!GetCommTimeouts (hnd, &ct))
8139 cp->status = STATUS_READ_ERROR;
8140 return STATUS_READ_ERROR;
8142 ct.ReadIntervalTimeout = 0;
8143 ct.ReadTotalTimeoutMultiplier = 0;
8144 ct.ReadTotalTimeoutConstant = 0;
8145 if (!SetCommTimeouts (hnd, &ct))
8147 cp->status = STATUS_READ_ERROR;
8148 return STATUS_READ_ERROR;
8151 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8153 if (GetLastError () != ERROR_IO_PENDING)
8155 cp->status = STATUS_READ_ERROR;
8156 return STATUS_READ_ERROR;
8158 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8160 cp->status = STATUS_READ_ERROR;
8161 return STATUS_READ_ERROR;
8165 else if (fd_info[fd].flags & FILE_SOCKET)
8167 unsigned long nblock = 0;
8168 /* We always want this to block, so temporarily disable NDELAY. */
8169 if (fd_info[fd].flags & FILE_NDELAY)
8170 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8172 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8174 if (fd_info[fd].flags & FILE_NDELAY)
8176 nblock = 1;
8177 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8181 if (rc == sizeof (char))
8182 cp->status = STATUS_READ_SUCCEEDED;
8183 else
8184 cp->status = STATUS_READ_FAILED;
8186 return cp->status;
8190 _sys_wait_accept (int fd)
8192 HANDLE hEv;
8193 child_process * cp;
8194 int rc;
8196 if (fd < 0 || fd >= MAXDESC)
8197 return STATUS_READ_ERROR;
8199 cp = fd_info[fd].cp;
8201 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8202 return STATUS_READ_ERROR;
8204 cp->status = STATUS_READ_FAILED;
8206 hEv = pfn_WSACreateEvent ();
8207 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8208 if (rc != SOCKET_ERROR)
8210 do {
8211 rc = WaitForSingleObject (hEv, 500);
8212 Sleep (5);
8213 } while (rc == WAIT_TIMEOUT
8214 && cp->status != STATUS_READ_ERROR
8215 && cp->char_avail);
8216 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8217 if (rc == WAIT_OBJECT_0)
8218 cp->status = STATUS_READ_SUCCEEDED;
8220 pfn_WSACloseEvent (hEv);
8222 return cp->status;
8226 _sys_wait_connect (int fd)
8228 HANDLE hEv;
8229 child_process * cp;
8230 int rc;
8232 if (fd < 0 || fd >= MAXDESC)
8233 return STATUS_READ_ERROR;
8235 cp = fd_info[fd].cp;
8236 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8237 return STATUS_READ_ERROR;
8239 cp->status = STATUS_READ_FAILED;
8241 hEv = pfn_WSACreateEvent ();
8242 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8243 if (rc != SOCKET_ERROR)
8245 do {
8246 rc = WaitForSingleObject (hEv, 500);
8247 Sleep (5);
8248 } while (rc == WAIT_TIMEOUT
8249 && cp->status != STATUS_READ_ERROR
8250 && cp->char_avail);
8251 if (rc == WAIT_OBJECT_0)
8253 /* We've got an event, but it could be a successful
8254 connection, or it could be a failure. Find out
8255 which one is it. */
8256 WSANETWORKEVENTS events;
8258 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8259 if ((events.lNetworkEvents & FD_CONNECT) != 0
8260 && events.iErrorCode[FD_CONNECT_BIT])
8262 cp->status = STATUS_CONNECT_FAILED;
8263 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8265 else
8267 cp->status = STATUS_READ_SUCCEEDED;
8268 cp->errcode = 0;
8271 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8273 else
8274 pfn_WSACloseEvent (hEv);
8276 return cp->status;
8280 sys_read (int fd, char * buffer, unsigned int count)
8282 int nchars;
8283 int to_read;
8284 DWORD waiting;
8285 char * orig_buffer = buffer;
8287 if (fd < 0)
8289 errno = EBADF;
8290 return -1;
8293 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8295 child_process *cp = fd_info[fd].cp;
8297 if ((fd_info[fd].flags & FILE_READ) == 0)
8299 errno = EBADF;
8300 return -1;
8303 nchars = 0;
8305 /* re-read CR carried over from last read */
8306 if (fd_info[fd].flags & FILE_LAST_CR)
8308 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8309 *buffer++ = 0x0d;
8310 count--;
8311 nchars++;
8312 fd_info[fd].flags &= ~FILE_LAST_CR;
8315 /* presence of a child_process structure means we are operating in
8316 non-blocking mode - otherwise we just call _read directly.
8317 Note that the child_process structure might be missing because
8318 reap_subprocess has been called; in this case the pipe is
8319 already broken, so calling _read on it is okay. */
8320 if (cp)
8322 int current_status = cp->status;
8324 switch (current_status)
8326 case STATUS_READ_FAILED:
8327 case STATUS_READ_ERROR:
8328 /* report normal EOF if nothing in buffer */
8329 if (nchars <= 0)
8330 fd_info[fd].flags |= FILE_AT_EOF;
8331 return nchars;
8333 case STATUS_READ_READY:
8334 case STATUS_READ_IN_PROGRESS:
8335 DebPrint (("sys_read called when read is in progress\n"));
8336 errno = EWOULDBLOCK;
8337 return -1;
8339 case STATUS_READ_SUCCEEDED:
8340 /* consume read-ahead char */
8341 *buffer++ = cp->chr;
8342 count--;
8343 nchars++;
8344 cp->status = STATUS_READ_ACKNOWLEDGED;
8345 ResetEvent (cp->char_avail);
8347 case STATUS_READ_ACKNOWLEDGED:
8348 case STATUS_CONNECT_FAILED:
8349 break;
8351 default:
8352 DebPrint (("sys_read: bad status %d\n", current_status));
8353 errno = EBADF;
8354 return -1;
8357 if (fd_info[fd].flags & FILE_PIPE)
8359 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8360 to_read = min (waiting, (DWORD) count);
8362 if (to_read > 0)
8363 nchars += _read (fd, buffer, to_read);
8365 else if (fd_info[fd].flags & FILE_SERIAL)
8367 HANDLE hnd = fd_info[fd].hnd;
8368 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8369 int rc = 0;
8370 COMMTIMEOUTS ct;
8372 if (count > 0)
8374 /* Configure timeouts for non-blocking read. */
8375 if (!GetCommTimeouts (hnd, &ct))
8377 errno = EIO;
8378 return -1;
8380 ct.ReadIntervalTimeout = MAXDWORD;
8381 ct.ReadTotalTimeoutMultiplier = 0;
8382 ct.ReadTotalTimeoutConstant = 0;
8383 if (!SetCommTimeouts (hnd, &ct))
8385 errno = EIO;
8386 return -1;
8389 if (!ResetEvent (ovl->hEvent))
8391 errno = EIO;
8392 return -1;
8394 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8396 if (GetLastError () != ERROR_IO_PENDING)
8398 errno = EIO;
8399 return -1;
8401 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8403 errno = EIO;
8404 return -1;
8407 nchars += rc;
8410 else /* FILE_SOCKET */
8412 if (winsock_lib == NULL) emacs_abort ();
8414 /* When a non-blocking 'connect' call fails,
8415 wait_reading_process_output detects this by calling
8416 'getpeername', and then attempts to obtain the connection
8417 error code by trying to read 1 byte from the socket. If
8418 we try to serve that read by calling 'recv' below, the
8419 error we get is a generic WSAENOTCONN, not the actual
8420 connection error. So instead, we use the actual error
8421 code stashed by '_sys_wait_connect' in cp->errcode.
8422 Alternatively, we could have used 'getsockopt', like on
8423 GNU/Linux, but: (a) I have no idea whether the winsock
8424 version could hang, as it does "on some systems" (see the
8425 comment in process.c); and (b) 'getsockopt' on Windows is
8426 documented to clear the socket error for the entire
8427 process, which I'm not sure is TRT; FIXME. */
8428 if (current_status == STATUS_CONNECT_FAILED
8429 && (fd_info[fd].flags & FILE_CONNECT) != 0
8430 && cp->errcode != 0)
8432 pfn_WSASetLastError (cp->errcode);
8433 set_errno ();
8434 return -1;
8436 /* Do the equivalent of a non-blocking read. */
8437 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8438 if (waiting == 0 && nchars == 0)
8440 errno = EWOULDBLOCK;
8441 return -1;
8444 if (waiting)
8446 /* always use binary mode for sockets */
8447 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8448 if (res == SOCKET_ERROR)
8450 set_errno ();
8451 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8452 errno, SOCK_HANDLE (fd)));
8453 return -1;
8455 nchars += res;
8459 else
8461 int nread = _read (fd, buffer, count);
8462 if (nread >= 0)
8463 nchars += nread;
8464 else if (nchars == 0)
8465 nchars = nread;
8468 if (nchars <= 0)
8469 fd_info[fd].flags |= FILE_AT_EOF;
8470 /* Perform text mode translation if required. */
8471 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8473 nchars = crlf_to_lf (nchars, orig_buffer);
8474 /* If buffer contains only CR, return that. To be absolutely
8475 sure we should attempt to read the next char, but in
8476 practice a CR to be followed by LF would not appear by
8477 itself in the buffer. */
8478 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8480 fd_info[fd].flags |= FILE_LAST_CR;
8481 nchars--;
8485 else
8486 nchars = _read (fd, buffer, count);
8488 return nchars;
8491 /* From w32xfns.c */
8492 extern HANDLE interrupt_handle;
8495 sys_write (int fd, const void * buffer, unsigned int count)
8497 int nchars;
8498 USE_SAFE_ALLOCA;
8500 if (fd < 0)
8502 errno = EBADF;
8503 return -1;
8506 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8508 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8510 errno = EBADF;
8511 return -1;
8514 /* Perform text mode translation if required. */
8515 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8517 char * tmpbuf;
8518 const unsigned char * src = buffer;
8519 unsigned char * dst;
8520 int nbytes = count;
8522 SAFE_NALLOCA (tmpbuf, 2, count);
8523 dst = tmpbuf;
8525 while (1)
8527 unsigned char *next;
8528 /* Copy next line or remaining bytes. */
8529 next = _memccpy (dst, src, '\n', nbytes);
8530 if (next)
8532 /* Copied one line ending with '\n'. */
8533 int copied = next - dst;
8534 nbytes -= copied;
8535 src += copied;
8536 /* Insert '\r' before '\n'. */
8537 next[-1] = '\r';
8538 next[0] = '\n';
8539 dst = next + 1;
8540 count++;
8542 else
8543 /* Copied remaining partial line -> now finished. */
8544 break;
8546 buffer = tmpbuf;
8550 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8552 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8553 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8554 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8555 DWORD active = 0;
8557 /* This is async (a.k.a. "overlapped") I/O, so the return value
8558 of FALSE from WriteFile means either an error or the output
8559 will be completed asynchronously (ERROR_IO_PENDING). */
8560 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8562 if (GetLastError () != ERROR_IO_PENDING)
8564 errno = EIO;
8565 nchars = -1;
8567 else
8569 /* Wait for the write to complete, and watch C-g while
8570 at that. */
8571 if (detect_input_pending ())
8572 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8573 INFINITE, QS_ALLINPUT);
8574 else
8575 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8576 switch (active)
8578 case WAIT_OBJECT_0:
8579 /* User pressed C-g, cancel write, then leave.
8580 Don't bother cleaning up as we may only get stuck
8581 in buggy drivers. */
8582 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8583 CancelIo (hnd);
8584 errno = EIO; /* Why not EINTR? */
8585 nchars = -1;
8586 break;
8587 case WAIT_OBJECT_0 + 1:
8588 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8590 errno = EIO;
8591 nchars = -1;
8593 break;
8598 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8600 unsigned long nblock = 0;
8601 if (winsock_lib == NULL) emacs_abort ();
8603 /* TODO: implement select() properly so non-blocking I/O works. */
8604 /* For now, make sure the write blocks. */
8605 if (fd_info[fd].flags & FILE_NDELAY)
8606 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8608 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8610 /* Set the socket back to non-blocking if it was before,
8611 for other operations that support it. */
8612 if (fd_info[fd].flags & FILE_NDELAY)
8614 nblock = 1;
8615 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8618 if (nchars == SOCKET_ERROR)
8620 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8621 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8622 set_errno ();
8625 else
8627 /* Some networked filesystems don't like too large writes, so
8628 break them into smaller chunks. See the Comments section of
8629 the MSDN documentation of WriteFile for details behind the
8630 choice of the value of CHUNK below. See also the thread
8631 http://thread.gmane.org/gmane.comp.version-control.git/145294
8632 in the git mailing list. */
8633 const unsigned char *p = buffer;
8634 const unsigned chunk = 30 * 1024 * 1024;
8636 nchars = 0;
8637 while (count > 0)
8639 unsigned this_chunk = count < chunk ? count : chunk;
8640 int n = _write (fd, p, this_chunk);
8642 nchars += n;
8643 if (n < 0)
8645 /* When there's no buffer space in a pipe that is in the
8646 non-blocking mode, _write returns ENOSPC. We return
8647 EAGAIN instead, which should trigger the logic in
8648 send_process that enters waiting loop and calls
8649 wait_reading_process_output to allow process input to
8650 be accepted during the wait. Those calls to
8651 wait_reading_process_output allow sys_select to
8652 notice when process input becomes available, thus
8653 avoiding deadlock whereby each side of the pipe is
8654 blocked on write, waiting for the other party to read
8655 its end of the pipe. */
8656 if (errno == ENOSPC
8657 && fd < MAXDESC
8658 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8659 == (FILE_PIPE | FILE_NDELAY)))
8660 errno = EAGAIN;
8661 nchars = n;
8662 break;
8664 else if (n < this_chunk)
8665 break;
8666 count -= n;
8667 p += n;
8671 SAFE_FREE ();
8672 return nchars;
8676 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8678 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8680 /* Return information about network interface IFNAME, or about all
8681 interfaces (if IFNAME is nil). */
8682 static Lisp_Object
8683 network_interface_get_info (Lisp_Object ifname)
8685 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8686 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8687 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8688 Lisp_Object res = Qnil;
8690 if (retval == ERROR_BUFFER_OVERFLOW)
8692 ainfo = xrealloc (ainfo, ainfo_len);
8693 retval = get_adapters_info (ainfo, &ainfo_len);
8696 if (retval == ERROR_SUCCESS)
8698 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8699 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8700 int if_num;
8701 struct sockaddr_in sa;
8703 /* For the below, we need some winsock functions, so make sure
8704 the winsock DLL is loaded. If we cannot successfully load
8705 it, they will have no use of the information we provide,
8706 anyway, so punt. */
8707 if (!winsock_lib && !init_winsock (1))
8708 goto done;
8710 for (adapter = ainfo; adapter; adapter = adapter->Next)
8712 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8713 u_long ip_addr;
8714 /* Present Unix-compatible interface names, instead of the
8715 Windows names, which are really GUIDs not readable by
8716 humans. */
8717 static const char *ifmt[] = {
8718 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8719 "lo", "ifx%d"
8721 enum {
8722 NONE = -1,
8723 ETHERNET = 0,
8724 TOKENRING = 1,
8725 FDDI = 2,
8726 PPP = 3,
8727 SLIP = 4,
8728 WLAN = 5,
8729 LOOPBACK = 6,
8730 OTHER_IF = 7
8731 } ifmt_idx;
8733 switch (adapter->Type)
8735 case MIB_IF_TYPE_ETHERNET:
8736 /* Windows before Vista reports wireless adapters as
8737 Ethernet. Work around by looking at the Description
8738 string. */
8739 if (strstr (adapter->Description, "Wireless "))
8741 ifmt_idx = WLAN;
8742 if_num = wlan_count++;
8744 else
8746 ifmt_idx = ETHERNET;
8747 if_num = eth_count++;
8749 break;
8750 case MIB_IF_TYPE_TOKENRING:
8751 ifmt_idx = TOKENRING;
8752 if_num = tr_count++;
8753 break;
8754 case MIB_IF_TYPE_FDDI:
8755 ifmt_idx = FDDI;
8756 if_num = fddi_count++;
8757 break;
8758 case MIB_IF_TYPE_PPP:
8759 ifmt_idx = PPP;
8760 if_num = ppp_count++;
8761 break;
8762 case MIB_IF_TYPE_SLIP:
8763 ifmt_idx = SLIP;
8764 if_num = sl_count++;
8765 break;
8766 case IF_TYPE_IEEE80211:
8767 ifmt_idx = WLAN;
8768 if_num = wlan_count++;
8769 break;
8770 case MIB_IF_TYPE_LOOPBACK:
8771 if (lo_count < 0)
8773 ifmt_idx = LOOPBACK;
8774 if_num = lo_count++;
8776 else
8777 ifmt_idx = NONE;
8778 break;
8779 default:
8780 ifmt_idx = OTHER_IF;
8781 if_num = ifx_count++;
8782 break;
8784 if (ifmt_idx == NONE)
8785 continue;
8786 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8788 sa.sin_family = AF_INET;
8789 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8790 if (ip_addr == INADDR_NONE)
8792 /* Bogus address, skip this interface. */
8793 continue;
8795 sa.sin_addr.s_addr = ip_addr;
8796 sa.sin_port = 0;
8797 if (NILP (ifname))
8798 res = Fcons (Fcons (build_string (namebuf),
8799 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8800 sizeof (struct sockaddr))),
8801 res);
8802 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8804 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8805 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8806 Lisp_Object flags = Qnil;
8807 int n;
8808 u_long net_mask;
8810 /* Flags. We guess most of them by type, since the
8811 Windows flags are different and hard to get by. */
8812 flags = Fcons (intern ("up"), flags);
8813 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8815 flags = Fcons (intern ("broadcast"), flags);
8816 flags = Fcons (intern ("multicast"), flags);
8818 flags = Fcons (intern ("running"), flags);
8819 if (ifmt_idx == PPP)
8821 flags = Fcons (intern ("pointopoint"), flags);
8822 flags = Fcons (intern ("noarp"), flags);
8824 if (adapter->HaveWins)
8825 flags = Fcons (intern ("WINS"), flags);
8826 if (adapter->DhcpEnabled)
8827 flags = Fcons (intern ("dynamic"), flags);
8829 res = Fcons (flags, res);
8831 /* Hardware address and its family. */
8832 for (n = 0; n < adapter->AddressLength; n++)
8833 p->contents[n] = make_number ((int) adapter->Address[n]);
8834 /* Windows does not support AF_LINK or AF_PACKET family
8835 of addresses. Use an arbitrary family number that is
8836 identical to what GNU/Linux returns. */
8837 res = Fcons (Fcons (make_number (1), hwaddr), res);
8839 /* Network mask. */
8840 sa.sin_family = AF_INET;
8841 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8842 if (net_mask != INADDR_NONE)
8844 sa.sin_addr.s_addr = net_mask;
8845 sa.sin_port = 0;
8846 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8847 sizeof (struct sockaddr)),
8848 res);
8850 else
8851 res = Fcons (Qnil, res);
8853 sa.sin_family = AF_INET;
8854 if (ip_addr != INADDR_NONE)
8856 /* Broadcast address is only reported by
8857 GetAdaptersAddresses, which is of limited
8858 availability. Generate it on our own. */
8859 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8861 sa.sin_addr.s_addr = bcast_addr;
8862 sa.sin_port = 0;
8863 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8864 sizeof (struct sockaddr)),
8865 res);
8867 /* IP address. */
8868 sa.sin_addr.s_addr = ip_addr;
8869 sa.sin_port = 0;
8870 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8871 sizeof (struct sockaddr)),
8872 res);
8874 else
8875 res = Fcons (Qnil, Fcons (Qnil, res));
8878 /* GetAdaptersInfo is documented to not report loopback
8879 interfaces, so we generate one out of thin air. */
8880 if (!lo_count)
8882 sa.sin_family = AF_INET;
8883 sa.sin_port = 0;
8884 if (NILP (ifname))
8886 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8887 res = Fcons (Fcons (build_string ("lo"),
8888 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8889 sizeof (struct sockaddr))),
8890 res);
8892 else if (strcmp (SSDATA (ifname), "lo") == 0)
8894 res = Fcons (Fcons (intern ("running"),
8895 Fcons (intern ("loopback"),
8896 Fcons (intern ("up"), Qnil))), Qnil);
8897 /* 772 is what 3 different GNU/Linux systems report for
8898 the loopback interface. */
8899 res = Fcons (Fcons (make_number (772),
8900 Fmake_vector (make_number (6),
8901 make_number (0))),
8902 res);
8903 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8904 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8905 sizeof (struct sockaddr)),
8906 res);
8907 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8908 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8909 sizeof (struct sockaddr)),
8910 res);
8911 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8912 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8913 sizeof (struct sockaddr)),
8914 res);
8920 done:
8921 xfree (ainfo);
8922 return res;
8925 Lisp_Object
8926 network_interface_list (void)
8928 return network_interface_get_info (Qnil);
8931 Lisp_Object
8932 network_interface_info (Lisp_Object ifname)
8934 CHECK_STRING (ifname);
8935 return network_interface_get_info (ifname);
8939 /* The Windows CRT functions are "optimized for speed", so they don't
8940 check for timezone and DST changes if they were last called less
8941 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8942 all Emacs features that repeatedly call time functions (e.g.,
8943 display-time) are in real danger of missing timezone and DST
8944 changes. Calling tzset before each localtime call fixes that. */
8945 struct tm *
8946 sys_localtime (const time_t *t)
8948 tzset ();
8949 return localtime (t);
8954 /* Try loading LIBRARY_ID from the file(s) specified in
8955 Vdynamic_library_alist. If the library is loaded successfully,
8956 return the handle of the DLL, and record the filename in the
8957 property :loaded-from of LIBRARY_ID. If the library could not be
8958 found, or when it was already loaded (because the handle is not
8959 recorded anywhere, and so is lost after use), return NULL.
8961 We could also save the handle in :loaded-from, but currently
8962 there's no use case for it. */
8963 HMODULE
8964 w32_delayed_load (Lisp_Object library_id)
8966 HMODULE dll_handle = NULL;
8968 CHECK_SYMBOL (library_id);
8970 if (CONSP (Vdynamic_library_alist)
8971 && NILP (Fassq (library_id, Vlibrary_cache)))
8973 Lisp_Object found = Qnil;
8974 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8976 if (CONSP (dlls))
8977 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8979 Lisp_Object dll = XCAR (dlls);
8980 char name[MAX_UTF8_PATH];
8981 DWORD res = -1;
8983 CHECK_STRING (dll);
8984 dll = ENCODE_FILE (dll);
8985 if (w32_unicode_filenames)
8987 wchar_t name_w[MAX_PATH];
8989 filename_to_utf16 (SSDATA (dll), name_w);
8990 dll_handle = LoadLibraryW (name_w);
8991 if (dll_handle)
8993 res = GetModuleFileNameW (dll_handle, name_w,
8994 sizeof (name_w));
8995 if (res > 0)
8996 filename_from_utf16 (name_w, name);
8999 else
9001 char name_a[MAX_PATH];
9003 filename_to_ansi (SSDATA (dll), name_a);
9004 dll_handle = LoadLibraryA (name_a);
9005 if (dll_handle)
9007 res = GetModuleFileNameA (dll_handle, name_a,
9008 sizeof (name_a));
9009 if (res > 0)
9010 filename_from_ansi (name_a, name);
9013 if (dll_handle)
9015 ptrdiff_t len = strlen (name);
9016 found = Fcons (dll,
9017 (res > 0)
9018 /* Possibly truncated */
9019 ? make_specified_string (name, -1, len, 1)
9020 : Qnil);
9021 /* This prevents thread start and end notifications
9022 from being sent to the DLL, for every thread we
9023 start. We don't need those notifications because
9024 threads we create never use any of these DLLs, only
9025 the main thread uses them. This is supposed to
9026 speed up thread creation. */
9027 DisableThreadLibraryCalls (dll_handle);
9028 break;
9032 Fput (library_id, QCloaded_from, found);
9035 return dll_handle;
9039 void
9040 check_windows_init_file (void)
9042 /* A common indication that Emacs is not installed properly is when
9043 it cannot find the Windows installation file. If this file does
9044 not exist in the expected place, tell the user. */
9046 if (!noninteractive && !inhibit_window_system
9047 /* Vload_path is not yet initialized when we are loading
9048 loadup.el. */
9049 && NILP (Vpurify_flag))
9051 Lisp_Object init_file;
9052 int fd;
9054 /* Implementation note: this function runs early during Emacs
9055 startup, before startup.el is run. So Vload_path is still in
9056 its initial unibyte form, but it holds UTF-8 encoded file
9057 names, since init_callproc was already called. So we do not
9058 need to ENCODE_FILE here, but we do need to convert the file
9059 names from UTF-8 to ANSI. */
9060 init_file = build_string ("term/w32-win");
9061 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9062 if (fd < 0)
9064 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9065 char *init_file_name = SDATA (init_file);
9066 char *load_path = SDATA (load_path_print);
9067 char *buffer = alloca (1024
9068 + strlen (init_file_name)
9069 + strlen (load_path));
9070 char *msg = buffer;
9071 int needed;
9073 sprintf (buffer,
9074 "The Emacs Windows initialization file \"%s.el\" "
9075 "could not be found in your Emacs installation. "
9076 "Emacs checked the following directories for this file:\n"
9077 "\n%s\n\n"
9078 "When Emacs cannot find this file, it usually means that it "
9079 "was not installed properly, or its distribution file was "
9080 "not unpacked properly.\nSee the README.W32 file in the "
9081 "top-level Emacs directory for more information.",
9082 init_file_name, load_path);
9083 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
9084 -1, NULL, 0);
9085 if (needed > 0)
9087 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9089 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
9090 msg_w, needed);
9091 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9092 NULL, 0, NULL, NULL);
9093 if (needed > 0)
9095 char *msg_a = alloca (needed + 1);
9097 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9098 NULL, NULL);
9099 msg = msg_a;
9102 MessageBox (NULL,
9103 msg,
9104 "Emacs Abort Dialog",
9105 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9106 /* Use the low-level system abort. */
9107 abort ();
9109 else
9111 _close (fd);
9116 void
9117 term_ntproc (int ignored)
9119 (void)ignored;
9121 term_timers ();
9123 /* shutdown the socket interface if necessary */
9124 term_winsock ();
9126 term_w32select ();
9129 void
9130 init_ntproc (int dumping)
9132 sigset_t initial_mask = 0;
9134 /* Initialize the socket interface now if available and requested by
9135 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9136 delayed until open-network-stream is called (w32-has-winsock can
9137 also be used to dynamically load or reload winsock).
9139 Conveniently, init_environment is called before us, so
9140 PRELOAD_WINSOCK can be set in the registry. */
9142 /* Always initialize this correctly. */
9143 winsock_lib = NULL;
9145 if (getenv ("PRELOAD_WINSOCK") != NULL)
9146 init_winsock (TRUE);
9148 /* Initial preparation for subprocess support: replace our standard
9149 handles with non-inheritable versions. */
9151 HANDLE parent;
9152 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9153 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9154 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9156 parent = GetCurrentProcess ();
9158 /* ignore errors when duplicating and closing; typically the
9159 handles will be invalid when running as a gui program. */
9160 DuplicateHandle (parent,
9161 GetStdHandle (STD_INPUT_HANDLE),
9162 parent,
9163 &stdin_save,
9165 FALSE,
9166 DUPLICATE_SAME_ACCESS);
9168 DuplicateHandle (parent,
9169 GetStdHandle (STD_OUTPUT_HANDLE),
9170 parent,
9171 &stdout_save,
9173 FALSE,
9174 DUPLICATE_SAME_ACCESS);
9176 DuplicateHandle (parent,
9177 GetStdHandle (STD_ERROR_HANDLE),
9178 parent,
9179 &stderr_save,
9181 FALSE,
9182 DUPLICATE_SAME_ACCESS);
9184 fclose (stdin);
9185 fclose (stdout);
9186 fclose (stderr);
9188 if (stdin_save != INVALID_HANDLE_VALUE)
9189 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9190 else
9191 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9192 _fdopen (0, "r");
9194 if (stdout_save != INVALID_HANDLE_VALUE)
9195 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9196 else
9197 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9198 _fdopen (1, "w");
9200 if (stderr_save != INVALID_HANDLE_VALUE)
9201 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9202 else
9203 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9204 _fdopen (2, "w");
9207 /* unfortunately, atexit depends on implementation of malloc */
9208 /* atexit (term_ntproc); */
9209 if (!dumping)
9211 /* Make sure we start with all signals unblocked. */
9212 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9213 signal (SIGABRT, term_ntproc);
9215 init_timers ();
9217 /* determine which drives are fixed, for GetCachedVolumeInformation */
9219 /* GetDriveType must have trailing backslash. */
9220 char drive[] = "A:\\";
9222 /* Loop over all possible drive letters */
9223 while (*drive <= 'Z')
9225 /* Record if this drive letter refers to a fixed drive. */
9226 fixed_drives[DRIVE_INDEX (*drive)] =
9227 (GetDriveType (drive) == DRIVE_FIXED);
9229 (*drive)++;
9232 /* Reset the volume info cache. */
9233 volume_cache = NULL;
9238 shutdown_handler ensures that buffers' autosave files are
9239 up to date when the user logs off, or the system shuts down.
9241 static BOOL WINAPI
9242 shutdown_handler (DWORD type)
9244 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9245 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9246 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9247 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9249 /* Shut down cleanly, making sure autosave files are up to date. */
9250 shut_down_emacs (0, Qnil);
9253 /* Allow other handlers to handle this signal. */
9254 return FALSE;
9257 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9258 NT, return a handle to GDI32.DLL. */
9259 HANDLE
9260 maybe_load_unicows_dll (void)
9262 if (os_subtype == OS_9X)
9264 HANDLE ret = LoadLibrary ("Unicows.dll");
9265 if (ret)
9267 /* These two functions are present on Windows 9X as stubs
9268 that always fail. We need the real implementations from
9269 UNICOWS.DLL, so we must call these functions through
9270 pointers, and assign the correct addresses to these
9271 pointers at program startup (see emacs.c, which calls
9272 this function early on). */
9273 pMultiByteToWideChar =
9274 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9275 pWideCharToMultiByte =
9276 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9277 return ret;
9279 else
9281 int button;
9283 button = MessageBox (NULL,
9284 "Emacs cannot load the UNICOWS.DLL library.\n"
9285 "This library is essential for using Emacs\n"
9286 "on this system. You need to install it.\n\n"
9287 "Emacs will exit when you click OK.",
9288 "Emacs cannot load UNICOWS.DLL",
9289 MB_ICONERROR | MB_TASKMODAL
9290 | MB_SETFOREGROUND | MB_OK);
9291 switch (button)
9293 case IDOK:
9294 default:
9295 exit (1);
9299 else
9301 /* On NT family of Windows, these two functions are always
9302 linked in, so we just assign their addresses to the 2
9303 pointers; no need for the LoadLibrary dance. */
9304 pMultiByteToWideChar = MultiByteToWideChar;
9305 pWideCharToMultiByte = WideCharToMultiByte;
9306 return LoadLibrary ("Gdi32.dll");
9311 globals_of_w32 is used to initialize those global variables that
9312 must always be initialized on startup even when the global variable
9313 initialized is non zero (see the function main in emacs.c).
9315 void
9316 globals_of_w32 (void)
9318 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9320 get_process_times_fn = (GetProcessTimes_Proc)
9321 GetProcAddress (kernel32, "GetProcessTimes");
9323 DEFSYM (QCloaded_from, ":loaded-from");
9325 g_b_init_is_windows_9x = 0;
9326 g_b_init_open_process_token = 0;
9327 g_b_init_get_token_information = 0;
9328 g_b_init_lookup_account_sid = 0;
9329 g_b_init_get_sid_sub_authority = 0;
9330 g_b_init_get_sid_sub_authority_count = 0;
9331 g_b_init_get_security_info = 0;
9332 g_b_init_get_file_security_w = 0;
9333 g_b_init_get_file_security_a = 0;
9334 g_b_init_get_security_descriptor_owner = 0;
9335 g_b_init_get_security_descriptor_group = 0;
9336 g_b_init_is_valid_sid = 0;
9337 g_b_init_create_toolhelp32_snapshot = 0;
9338 g_b_init_process32_first = 0;
9339 g_b_init_process32_next = 0;
9340 g_b_init_open_thread_token = 0;
9341 g_b_init_impersonate_self = 0;
9342 g_b_init_revert_to_self = 0;
9343 g_b_init_get_process_memory_info = 0;
9344 g_b_init_get_process_working_set_size = 0;
9345 g_b_init_global_memory_status = 0;
9346 g_b_init_global_memory_status_ex = 0;
9347 g_b_init_equal_sid = 0;
9348 g_b_init_copy_sid = 0;
9349 g_b_init_get_length_sid = 0;
9350 g_b_init_get_native_system_info = 0;
9351 g_b_init_get_system_times = 0;
9352 g_b_init_create_symbolic_link_w = 0;
9353 g_b_init_create_symbolic_link_a = 0;
9354 g_b_init_get_security_descriptor_dacl = 0;
9355 g_b_init_convert_sd_to_sddl = 0;
9356 g_b_init_convert_sddl_to_sd = 0;
9357 g_b_init_is_valid_security_descriptor = 0;
9358 g_b_init_set_file_security_w = 0;
9359 g_b_init_set_file_security_a = 0;
9360 g_b_init_set_named_security_info_w = 0;
9361 g_b_init_set_named_security_info_a = 0;
9362 g_b_init_get_adapters_info = 0;
9363 g_b_init_compare_string_w = 0;
9364 num_of_processors = 0;
9365 /* The following sets a handler for shutdown notifications for
9366 console apps. This actually applies to Emacs in both console and
9367 GUI modes, since we had to fool windows into thinking emacs is a
9368 console application to get console mode to work. */
9369 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9371 /* "None" is the default group name on standalone workstations. */
9372 strcpy (dflt_group_name, "None");
9374 /* Reset, in case it has some value inherited from dump time. */
9375 w32_stat_get_owner_group = 0;
9377 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9378 (a.k.a. "wide") APIs to invoke functions that accept file
9379 names. */
9380 if (is_windows_9x ())
9381 w32_unicode_filenames = 0;
9382 else
9383 w32_unicode_filenames = 1;
9385 #ifdef HAVE_MODULES
9386 extern void dynlib_reset_last_error (void);
9387 dynlib_reset_last_error ();
9388 #endif
9391 /* For make-serial-process */
9393 serial_open (Lisp_Object port_obj)
9395 char *port = SSDATA (port_obj);
9396 HANDLE hnd;
9397 child_process *cp;
9398 int fd = -1;
9400 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9401 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9402 if (hnd == INVALID_HANDLE_VALUE)
9403 error ("Could not open %s", port);
9404 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9405 if (fd == -1)
9406 error ("Could not open %s", port);
9408 cp = new_child ();
9409 if (!cp)
9410 error ("Could not create child process");
9411 cp->fd = fd;
9412 cp->status = STATUS_READ_ACKNOWLEDGED;
9413 fd_info[ fd ].hnd = hnd;
9414 fd_info[ fd ].flags |=
9415 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9416 if (fd_info[ fd ].cp != NULL)
9418 error ("fd_info[fd = %d] is already in use", fd);
9420 fd_info[ fd ].cp = cp;
9421 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9422 if (cp->ovl_read.hEvent == NULL)
9423 error ("Could not create read event");
9424 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9425 if (cp->ovl_write.hEvent == NULL)
9426 error ("Could not create write event");
9428 return fd;
9431 /* For serial-process-configure */
9432 void
9433 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9435 Lisp_Object childp2 = Qnil;
9436 Lisp_Object tem = Qnil;
9437 HANDLE hnd;
9438 DCB dcb;
9439 COMMTIMEOUTS ct;
9440 char summary[4] = "???"; /* This usually becomes "8N1". */
9442 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9443 error ("Not a serial process");
9444 hnd = fd_info[ p->outfd ].hnd;
9446 childp2 = Fcopy_sequence (p->childp);
9448 /* Initialize timeouts for blocking read and blocking write. */
9449 if (!GetCommTimeouts (hnd, &ct))
9450 error ("GetCommTimeouts() failed");
9451 ct.ReadIntervalTimeout = 0;
9452 ct.ReadTotalTimeoutMultiplier = 0;
9453 ct.ReadTotalTimeoutConstant = 0;
9454 ct.WriteTotalTimeoutMultiplier = 0;
9455 ct.WriteTotalTimeoutConstant = 0;
9456 if (!SetCommTimeouts (hnd, &ct))
9457 error ("SetCommTimeouts() failed");
9458 /* Read port attributes and prepare default configuration. */
9459 memset (&dcb, 0, sizeof (dcb));
9460 dcb.DCBlength = sizeof (DCB);
9461 if (!GetCommState (hnd, &dcb))
9462 error ("GetCommState() failed");
9463 dcb.fBinary = TRUE;
9464 dcb.fNull = FALSE;
9465 dcb.fAbortOnError = FALSE;
9466 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9467 dcb.ErrorChar = 0;
9468 dcb.EofChar = 0;
9469 dcb.EvtChar = 0;
9471 /* Configure speed. */
9472 if (!NILP (Fplist_member (contact, QCspeed)))
9473 tem = Fplist_get (contact, QCspeed);
9474 else
9475 tem = Fplist_get (p->childp, QCspeed);
9476 CHECK_NUMBER (tem);
9477 dcb.BaudRate = XINT (tem);
9478 childp2 = Fplist_put (childp2, QCspeed, tem);
9480 /* Configure bytesize. */
9481 if (!NILP (Fplist_member (contact, QCbytesize)))
9482 tem = Fplist_get (contact, QCbytesize);
9483 else
9484 tem = Fplist_get (p->childp, QCbytesize);
9485 if (NILP (tem))
9486 tem = make_number (8);
9487 CHECK_NUMBER (tem);
9488 if (XINT (tem) != 7 && XINT (tem) != 8)
9489 error (":bytesize must be nil (8), 7, or 8");
9490 dcb.ByteSize = XINT (tem);
9491 summary[0] = XINT (tem) + '0';
9492 childp2 = Fplist_put (childp2, QCbytesize, tem);
9494 /* Configure parity. */
9495 if (!NILP (Fplist_member (contact, QCparity)))
9496 tem = Fplist_get (contact, QCparity);
9497 else
9498 tem = Fplist_get (p->childp, QCparity);
9499 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9500 error (":parity must be nil (no parity), `even', or `odd'");
9501 dcb.fParity = FALSE;
9502 dcb.Parity = NOPARITY;
9503 dcb.fErrorChar = FALSE;
9504 if (NILP (tem))
9506 summary[1] = 'N';
9508 else if (EQ (tem, Qeven))
9510 summary[1] = 'E';
9511 dcb.fParity = TRUE;
9512 dcb.Parity = EVENPARITY;
9513 dcb.fErrorChar = TRUE;
9515 else if (EQ (tem, Qodd))
9517 summary[1] = 'O';
9518 dcb.fParity = TRUE;
9519 dcb.Parity = ODDPARITY;
9520 dcb.fErrorChar = TRUE;
9522 childp2 = Fplist_put (childp2, QCparity, tem);
9524 /* Configure stopbits. */
9525 if (!NILP (Fplist_member (contact, QCstopbits)))
9526 tem = Fplist_get (contact, QCstopbits);
9527 else
9528 tem = Fplist_get (p->childp, QCstopbits);
9529 if (NILP (tem))
9530 tem = make_number (1);
9531 CHECK_NUMBER (tem);
9532 if (XINT (tem) != 1 && XINT (tem) != 2)
9533 error (":stopbits must be nil (1 stopbit), 1, or 2");
9534 summary[2] = XINT (tem) + '0';
9535 if (XINT (tem) == 1)
9536 dcb.StopBits = ONESTOPBIT;
9537 else if (XINT (tem) == 2)
9538 dcb.StopBits = TWOSTOPBITS;
9539 childp2 = Fplist_put (childp2, QCstopbits, tem);
9541 /* Configure flowcontrol. */
9542 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9543 tem = Fplist_get (contact, QCflowcontrol);
9544 else
9545 tem = Fplist_get (p->childp, QCflowcontrol);
9546 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9547 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9548 dcb.fOutxCtsFlow = FALSE;
9549 dcb.fOutxDsrFlow = FALSE;
9550 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9551 dcb.fDsrSensitivity = FALSE;
9552 dcb.fTXContinueOnXoff = FALSE;
9553 dcb.fOutX = FALSE;
9554 dcb.fInX = FALSE;
9555 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9556 dcb.XonChar = 17; /* Control-Q */
9557 dcb.XoffChar = 19; /* Control-S */
9558 if (NILP (tem))
9560 /* Already configured. */
9562 else if (EQ (tem, Qhw))
9564 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9565 dcb.fOutxCtsFlow = TRUE;
9567 else if (EQ (tem, Qsw))
9569 dcb.fOutX = TRUE;
9570 dcb.fInX = TRUE;
9572 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9574 /* Activate configuration. */
9575 if (!SetCommState (hnd, &dcb))
9576 error ("SetCommState() failed");
9578 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9579 pset_childp (p, childp2);
9582 /* For make-pipe-process */
9583 void
9584 register_aux_fd (int infd)
9586 child_process *cp;
9588 cp = new_child ();
9589 if (!cp)
9590 error ("Could not create child process");
9591 cp->fd = infd;
9592 cp->status = STATUS_READ_ACKNOWLEDGED;
9594 if (fd_info[ infd ].cp != NULL)
9596 error ("fd_info[fd = %d] is already in use", infd);
9598 fd_info[ infd ].cp = cp;
9599 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9602 #ifdef HAVE_GNUTLS
9604 ssize_t
9605 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9607 int n, err;
9608 struct Lisp_Process *process = (struct Lisp_Process *)p;
9609 int fd = process->infd;
9611 n = sys_read (fd, (char*)buf, sz);
9613 if (n >= 0)
9614 return n;
9616 err = errno;
9618 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9619 if (err == EWOULDBLOCK)
9620 err = EAGAIN;
9622 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9624 return -1;
9627 ssize_t
9628 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9630 struct Lisp_Process *process = (struct Lisp_Process *)p;
9631 int fd = process->outfd;
9632 ssize_t n = sys_write (fd, buf, sz);
9634 /* 0 or more bytes written means everything went fine. */
9635 if (n >= 0)
9636 return n;
9638 /* Negative bytes written means we got an error in errno.
9639 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9640 emacs_gnutls_transport_set_errno (process->gnutls_state,
9641 errno == EWOULDBLOCK ? EAGAIN : errno);
9643 return -1;
9645 #endif /* HAVE_GNUTLS */
9647 /* end of w32.c */