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