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