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