(getpwnam, getpwuid): Add prototypes.
[bpt/emacs.git] / src / w32.c
CommitLineData
e9e23e23 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
302f0b29 2 Copyright (C) 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
95ed0025 3
3b7ad313
EN
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
95ed0025
RS
20
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22*/
23
00b3b7b3 24
76b3903d 25#include <stddef.h> /* for offsetof */
95ed0025
RS
26#include <stdlib.h>
27#include <stdio.h>
28#include <io.h>
480b0c5b 29#include <errno.h>
95ed0025
RS
30#include <fcntl.h>
31#include <ctype.h>
480b0c5b 32#include <signal.h>
b3308d2e 33#include <sys/file.h>
480b0c5b 34#include <sys/time.h>
16bb7578 35#include <sys/utime.h>
480b0c5b
GV
36
37/* must include CRT headers *before* config.h */
4838e624
PJ
38
39#ifdef HAVE_CONFIG_H
40#include <config.h>
41#endif
42
480b0c5b
GV
43#undef access
44#undef chdir
45#undef chmod
46#undef creat
47#undef ctime
48#undef fopen
49#undef link
50#undef mkdir
51#undef mktemp
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
95ed0025 63
d8fcc1b9
AI
64#undef strerror
65
95ed0025 66#include "lisp.h"
95ed0025
RS
67
68#include <pwd.h>
3d19b645 69#include <grp.h>
95ed0025 70
971bce75
AI
71#ifdef __GNUC__
72#define _ANONYMOUS_UNION
73#define _ANONYMOUS_STRUCT
74#endif
480b0c5b 75#include <windows.h>
00b3b7b3 76
480b0c5b
GV
77#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
78#include <sys/socket.h>
79#undef socket
80#undef bind
81#undef connect
82#undef htons
83#undef ntohs
84#undef inet_addr
85#undef gethostname
86#undef gethostbyname
87#undef getservbyname
ecd270eb 88#undef getpeername
380961a6 89#undef shutdown
962955c5
JR
90#undef setsockopt
91#undef listen
92#undef getsockname
93#undef accept
94#undef recvfrom
95#undef sendto
480b0c5b 96#endif
00b3b7b3 97
489f9371 98#include "w32.h"
480b0c5b 99#include "ndir.h"
489f9371 100#include "w32heap.h"
253574a6
JR
101#include "systime.h"
102
9785d95b
BK
103void globals_of_w32 ();
104
76b3903d
GV
105extern Lisp_Object Vw32_downcase_file_names;
106extern Lisp_Object Vw32_generate_fake_inodes;
107extern Lisp_Object Vw32_get_true_file_attributes;
e0c181dd 108extern int w32_num_mouse_buttons;
76b3903d 109
18e070ac 110\f
9785d95b
BK
111/*
112 Initialization states
113 */
114static BOOL g_b_init_is_windows_9x;
115static BOOL g_b_init_open_process_token;
116static BOOL g_b_init_get_token_information;
117static BOOL g_b_init_lookup_account_sid;
118static BOOL g_b_init_get_sid_identifier_authority;
119
f60ae425
BK
120/*
121 BEGIN: Wrapper functions around OpenProcessToken
122 and other functions in advapi32.dll that are only
123 supported in Windows NT / 2k / XP
124*/
125 /* ** Function pointer typedefs ** */
126typedef BOOL (WINAPI * OpenProcessToken_Proc) (
127 HANDLE ProcessHandle,
128 DWORD DesiredAccess,
129 PHANDLE TokenHandle);
130typedef BOOL (WINAPI * GetTokenInformation_Proc) (
131 HANDLE TokenHandle,
132 TOKEN_INFORMATION_CLASS TokenInformationClass,
133 LPVOID TokenInformation,
134 DWORD TokenInformationLength,
135 PDWORD ReturnLength);
136#ifdef _UNICODE
137const char * const LookupAccountSid_Name = "LookupAccountSidW";
138#else
139const char * const LookupAccountSid_Name = "LookupAccountSidA";
140#endif
141typedef BOOL (WINAPI * LookupAccountSid_Proc) (
142 LPCTSTR lpSystemName,
143 PSID Sid,
144 LPTSTR Name,
145 LPDWORD cbName,
146 LPTSTR DomainName,
147 LPDWORD cbDomainName,
148 PSID_NAME_USE peUse);
149typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
150 PSID pSid);
151
152 /* ** A utility function ** */
153static BOOL is_windows_9x ()
154{
9785d95b 155 static BOOL s_b_ret=0;
f60ae425 156 OSVERSIONINFO os_ver;
9785d95b 157 if (g_b_init_is_windows_9x == 0)
f60ae425 158 {
9785d95b
BK
159 g_b_init_is_windows_9x = 1;
160 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
161 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
162 if (GetVersionEx (&os_ver))
163 {
164 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
165 }
f60ae425 166 }
9785d95b 167 return s_b_ret;
f60ae425
BK
168}
169
170 /* ** The wrapper functions ** */
171
172BOOL WINAPI open_process_token (
173 HANDLE ProcessHandle,
174 DWORD DesiredAccess,
175 PHANDLE TokenHandle)
176{
9785d95b 177 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
f60ae425
BK
178 HMODULE hm_advapi32 = NULL;
179 if (is_windows_9x () == TRUE)
180 {
181 return FALSE;
182 }
9785d95b
BK
183 if (g_b_init_open_process_token == 0)
184 {
185 g_b_init_open_process_token = 1;
186 hm_advapi32 = LoadLibrary ("Advapi32.dll");
187 s_pfn_Open_Process_Token =
188 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
189 }
190 if (s_pfn_Open_Process_Token == NULL)
f60ae425
BK
191 {
192 return FALSE;
193 }
194 return (
9785d95b 195 s_pfn_Open_Process_Token (
f60ae425
BK
196 ProcessHandle,
197 DesiredAccess,
198 TokenHandle)
199 );
200}
201
202BOOL WINAPI get_token_information (
203 HANDLE TokenHandle,
204 TOKEN_INFORMATION_CLASS TokenInformationClass,
205 LPVOID TokenInformation,
206 DWORD TokenInformationLength,
207 PDWORD ReturnLength)
208{
9785d95b 209 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
f60ae425
BK
210 HMODULE hm_advapi32 = NULL;
211 if (is_windows_9x () == TRUE)
212 {
213 return FALSE;
214 }
9785d95b
BK
215 if (g_b_init_get_token_information == 0)
216 {
217 g_b_init_get_token_information = 1;
218 hm_advapi32 = LoadLibrary ("Advapi32.dll");
219 s_pfn_Get_Token_Information =
220 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
221 }
222 if (s_pfn_Get_Token_Information == NULL)
f60ae425
BK
223 {
224 return FALSE;
225 }
226 return (
9785d95b 227 s_pfn_Get_Token_Information (
f60ae425
BK
228 TokenHandle,
229 TokenInformationClass,
230 TokenInformation,
231 TokenInformationLength,
232 ReturnLength)
233 );
234}
235
236BOOL WINAPI lookup_account_sid (
237 LPCTSTR lpSystemName,
238 PSID Sid,
239 LPTSTR Name,
240 LPDWORD cbName,
241 LPTSTR DomainName,
242 LPDWORD cbDomainName,
243 PSID_NAME_USE peUse)
244{
9785d95b 245 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
f60ae425
BK
246 HMODULE hm_advapi32 = NULL;
247 if (is_windows_9x () == TRUE)
248 {
249 return FALSE;
250 }
9785d95b
BK
251 if (g_b_init_lookup_account_sid == 0)
252 {
253 g_b_init_lookup_account_sid = 1;
254 hm_advapi32 = LoadLibrary ("Advapi32.dll");
255 s_pfn_Lookup_Account_Sid =
256 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
257 }
258 if (s_pfn_Lookup_Account_Sid == NULL)
f60ae425
BK
259 {
260 return FALSE;
261 }
262 return (
9785d95b 263 s_pfn_Lookup_Account_Sid (
f60ae425
BK
264 lpSystemName,
265 Sid,
266 Name,
267 cbName,
268 DomainName,
269 cbDomainName,
270 peUse)
271 );
272}
273
274PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
275 PSID pSid)
276{
9785d95b 277 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
f60ae425
BK
278 HMODULE hm_advapi32 = NULL;
279 if (is_windows_9x () == TRUE)
280 {
281 return NULL;
282 }
9785d95b
BK
283 if (g_b_init_get_sid_identifier_authority == 0)
284 {
285 g_b_init_get_sid_identifier_authority = 1;
286 hm_advapi32 = LoadLibrary ("Advapi32.dll");
287 s_pfn_Get_Sid_Identifier_Authority =
288 (GetSidIdentifierAuthority_Proc) GetProcAddress (
289 hm_advapi32, "GetSidIdentifierAuthority");
290 }
291 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
f60ae425
BK
292 {
293 return NULL;
294 }
9785d95b 295 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
f60ae425
BK
296}
297
298/*
299 END: Wrapper functions around OpenProcessToken
300 and other functions in advapi32.dll that are only
301 supported in Windows NT / 2k / XP
302*/
303
304\f
18e070ac
AI
305/* Equivalent of strerror for W32 error codes. */
306char *
307w32_strerror (int error_no)
308{
309 static char buf[500];
310
311 if (error_no == 0)
312 error_no = GetLastError ();
313
314 buf[0] = '\0';
315 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
316 error_no,
317 0, /* choose most suitable language */
318 buf, sizeof (buf), NULL))
319 sprintf (buf, "w32 error %u", error_no);
320 return buf;
321}
322
76b3903d 323static char startup_dir[MAXPATHLEN];
00b3b7b3 324
95ed0025 325/* Get the current working directory. */
480b0c5b 326char *
95ed0025
RS
327getwd (char *dir)
328{
76b3903d 329#if 0
480b0c5b
GV
330 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
331 return dir;
332 return NULL;
76b3903d
GV
333#else
334 /* Emacs doesn't actually change directory itself, and we want to
335 force our real wd to be where emacs.exe is to avoid unnecessary
336 conflicts when trying to rename or delete directories. */
337 strcpy (dir, startup_dir);
338 return dir;
339#endif
95ed0025
RS
340}
341
480b0c5b 342#ifndef HAVE_SOCKETS
95ed0025
RS
343/* Emulate gethostname. */
344int
345gethostname (char *buffer, int size)
346{
177c0ea7 347 /* NT only allows small host names, so the buffer is
95ed0025
RS
348 certainly large enough. */
349 return !GetComputerName (buffer, &size);
350}
480b0c5b 351#endif /* HAVE_SOCKETS */
95ed0025
RS
352
353/* Emulate getloadavg. */
354int
355getloadavg (double loadavg[], int nelem)
356{
357 int i;
358
359 /* A faithful emulation is going to have to be saved for a rainy day. */
177c0ea7 360 for (i = 0; i < nelem; i++)
95ed0025
RS
361 {
362 loadavg[i] = 0.0;
363 }
364 return i;
365}
366
480b0c5b 367/* Emulate getpwuid, getpwnam and others. */
95ed0025 368
051fe60d
GV
369#define PASSWD_FIELD_SIZE 256
370
371static char the_passwd_name[PASSWD_FIELD_SIZE];
372static char the_passwd_passwd[PASSWD_FIELD_SIZE];
373static char the_passwd_gecos[PASSWD_FIELD_SIZE];
374static char the_passwd_dir[PASSWD_FIELD_SIZE];
375static char the_passwd_shell[PASSWD_FIELD_SIZE];
95ed0025 376
177c0ea7 377static struct passwd the_passwd =
95ed0025
RS
378{
379 the_passwd_name,
380 the_passwd_passwd,
381 0,
382 0,
383 0,
384 the_passwd_gecos,
385 the_passwd_dir,
386 the_passwd_shell,
387};
388
3d19b645
LH
389static struct group the_group =
390{
391 /* There are no groups on NT, so we just return "root" as the
392 group name. */
393 "root",
394};
395
177c0ea7
JB
396int
397getuid ()
398{
480b0c5b
GV
399 return the_passwd.pw_uid;
400}
401
177c0ea7
JB
402int
403geteuid ()
404{
480b0c5b
GV
405 /* I could imagine arguing for checking to see whether the user is
406 in the Administrators group and returning a UID of 0 for that
407 case, but I don't know how wise that would be in the long run. */
177c0ea7 408 return getuid ();
480b0c5b
GV
409}
410
177c0ea7
JB
411int
412getgid ()
413{
480b0c5b
GV
414 return the_passwd.pw_gid;
415}
416
177c0ea7
JB
417int
418getegid ()
419{
480b0c5b
GV
420 return getgid ();
421}
422
95ed0025
RS
423struct passwd *
424getpwuid (int uid)
425{
480b0c5b
GV
426 if (uid == the_passwd.pw_uid)
427 return &the_passwd;
428 return NULL;
95ed0025
RS
429}
430
3d19b645
LH
431struct group *
432getgrgid (gid_t gid)
433{
434 return &the_group;
435}
436
95ed0025
RS
437struct passwd *
438getpwnam (char *name)
439{
440 struct passwd *pw;
177c0ea7 441
95ed0025
RS
442 pw = getpwuid (getuid ());
443 if (!pw)
444 return pw;
445
480b0c5b 446 if (stricmp (name, pw->pw_name))
95ed0025
RS
447 return NULL;
448
449 return pw;
450}
451
480b0c5b
GV
452void
453init_user_info ()
95ed0025 454{
480b0c5b
GV
455 /* Find the user's real name by opening the process token and
456 looking up the name associated with the user-sid in that token.
457
458 Use the relative portion of the identifier authority value from
459 the user-sid as the user id value (same for group id using the
460 primary group sid from the process token). */
461
462 char user_sid[256], name[256], domain[256];
463 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
464 HANDLE token = NULL;
465 SID_NAME_USE user_type;
466
f60ae425
BK
467 if (
468 open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
469 && get_token_information (
470 token, TokenUser,
480b0c5b 471 (PVOID) user_sid, sizeof (user_sid), &trash)
f60ae425
BK
472 && lookup_account_sid (
473 NULL, *((PSID *) user_sid), name, &length,
474 domain, &dlength, &user_type)
475 )
d1c1c3d2 476 {
480b0c5b
GV
477 strcpy (the_passwd.pw_name, name);
478 /* Determine a reasonable uid value. */
479 if (stricmp ("administrator", name) == 0)
480 {
481 the_passwd.pw_uid = 0;
482 the_passwd.pw_gid = 0;
483 }
484 else
485 {
486 SID_IDENTIFIER_AUTHORITY * pSIA;
487
f60ae425 488 pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
480b0c5b
GV
489 /* I believe the relative portion is the last 4 bytes (of 6)
490 with msb first. */
491 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
492 (pSIA->Value[3] << 16) +
493 (pSIA->Value[4] << 8) +
494 (pSIA->Value[5] << 0));
495 /* restrict to conventional uid range for normal users */
496 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
497
498 /* Get group id */
f60ae425 499 if (get_token_information (token, TokenPrimaryGroup,
480b0c5b
GV
500 (PVOID) user_sid, sizeof (user_sid), &trash))
501 {
502 SID_IDENTIFIER_AUTHORITY * pSIA;
503
f60ae425 504 pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
480b0c5b
GV
505 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
506 (pSIA->Value[3] << 16) +
507 (pSIA->Value[4] << 8) +
508 (pSIA->Value[5] << 0));
509 /* I don't know if this is necessary, but for safety... */
510 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
511 }
512 else
513 the_passwd.pw_gid = the_passwd.pw_uid;
514 }
515 }
516 /* If security calls are not supported (presumably because we
517 are running under Windows 95), fallback to this. */
518 else if (GetUserName (name, &length))
519 {
520 strcpy (the_passwd.pw_name, name);
521 if (stricmp ("administrator", name) == 0)
522 the_passwd.pw_uid = 0;
523 else
524 the_passwd.pw_uid = 123;
525 the_passwd.pw_gid = the_passwd.pw_uid;
526 }
527 else
528 {
529 strcpy (the_passwd.pw_name, "unknown");
530 the_passwd.pw_uid = 123;
531 the_passwd.pw_gid = 123;
d1c1c3d2 532 }
95ed0025 533
480b0c5b
GV
534 /* Ensure HOME and SHELL are defined. */
535 if (getenv ("HOME") == NULL)
ca149beb 536 abort ();
480b0c5b 537 if (getenv ("SHELL") == NULL)
ca149beb 538 abort ();
95ed0025 539
480b0c5b
GV
540 /* Set dir and shell from environment variables. */
541 strcpy (the_passwd.pw_dir, getenv ("HOME"));
542 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
bd4a449f 543
480b0c5b
GV
544 if (token)
545 CloseHandle (token);
95ed0025
RS
546}
547
95ed0025 548int
480b0c5b 549random ()
95ed0025 550{
480b0c5b
GV
551 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
552 return ((rand () << 15) | rand ());
95ed0025
RS
553}
554
95ed0025 555void
480b0c5b 556srandom (int seed)
95ed0025 557{
480b0c5b 558 srand (seed);
95ed0025
RS
559}
560
76b3903d 561
cbe39279
RS
562/* Normalize filename by converting all path separators to
563 the specified separator. Also conditionally convert upper
564 case path name components to lower case. */
565
566static void
567normalize_filename (fp, path_sep)
568 register char *fp;
569 char path_sep;
570{
571 char sep;
572 char *elem;
573
5162ffce
MB
574 /* Always lower-case drive letters a-z, even if the filesystem
575 preserves case in filenames.
576 This is so filenames can be compared by string comparison
577 functions that are case-sensitive. Even case-preserving filesystems
578 do not distinguish case in drive letters. */
579 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
580 {
581 *fp += 'a' - 'A';
582 fp += 2;
583 }
584
fbd6baed 585 if (NILP (Vw32_downcase_file_names))
cbe39279
RS
586 {
587 while (*fp)
588 {
589 if (*fp == '/' || *fp == '\\')
590 *fp = path_sep;
591 fp++;
592 }
593 return;
594 }
595
596 sep = path_sep; /* convert to this path separator */
597 elem = fp; /* start of current path element */
598
599 do {
600 if (*fp >= 'a' && *fp <= 'z')
601 elem = 0; /* don't convert this element */
602
603 if (*fp == 0 || *fp == ':')
604 {
605 sep = *fp; /* restore current separator (or 0) */
606 *fp = '/'; /* after conversion of this element */
607 }
608
609 if (*fp == '/' || *fp == '\\')
610 {
611 if (elem && elem != fp)
612 {
613 *fp = 0; /* temporary end of string */
614 _strlwr (elem); /* while we convert to lower case */
615 }
616 *fp = sep; /* convert (or restore) path separator */
617 elem = fp + 1; /* next element starts after separator */
618 sep = path_sep;
619 }
620 } while (*fp++);
621}
622
480b0c5b 623/* Destructively turn backslashes into slashes. */
95ed0025 624void
480b0c5b
GV
625dostounix_filename (p)
626 register char *p;
95ed0025 627{
cbe39279 628 normalize_filename (p, '/');
95ed0025
RS
629}
630
480b0c5b 631/* Destructively turn slashes into backslashes. */
95ed0025 632void
480b0c5b
GV
633unixtodos_filename (p)
634 register char *p;
95ed0025 635{
cbe39279 636 normalize_filename (p, '\\');
95ed0025
RS
637}
638
480b0c5b
GV
639/* Remove all CR's that are followed by a LF.
640 (From msdos.c...probably should figure out a way to share it,
641 although this code isn't going to ever change.) */
35f0d482 642int
480b0c5b
GV
643crlf_to_lf (n, buf)
644 register int n;
645 register unsigned char *buf;
35f0d482 646{
480b0c5b
GV
647 unsigned char *np = buf;
648 unsigned char *startp = buf;
649 unsigned char *endp = buf + n;
35f0d482 650
480b0c5b
GV
651 if (n == 0)
652 return n;
653 while (buf < endp - 1)
95ed0025 654 {
480b0c5b
GV
655 if (*buf == 0x0d)
656 {
657 if (*(++buf) != 0x0a)
658 *np++ = 0x0d;
659 }
660 else
661 *np++ = *buf++;
95ed0025 662 }
480b0c5b
GV
663 if (buf < endp)
664 *np++ = *buf++;
665 return np - startp;
95ed0025
RS
666}
667
76b3903d
GV
668/* Parse the root part of file name, if present. Return length and
669 optionally store pointer to char after root. */
670static int
671parse_root (char * name, char ** pPath)
672{
673 char * start = name;
674
675 if (name == NULL)
676 return 0;
677
678 /* find the root name of the volume if given */
679 if (isalpha (name[0]) && name[1] == ':')
680 {
681 /* skip past drive specifier */
682 name += 2;
683 if (IS_DIRECTORY_SEP (name[0]))
684 name++;
685 }
686 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
687 {
688 int slashes = 2;
689 name += 2;
690 do
691 {
692 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
693 break;
694 name++;
695 }
696 while ( *name );
697 if (IS_DIRECTORY_SEP (name[0]))
698 name++;
699 }
700
701 if (pPath)
702 *pPath = name;
703
704 return name - start;
705}
706
707/* Get long base name for name; name is assumed to be absolute. */
708static int
709get_long_basename (char * name, char * buf, int size)
710{
711 WIN32_FIND_DATA find_data;
712 HANDLE dir_handle;
713 int len = 0;
714
9ab8560d 715 /* must be valid filename, no wild cards or other invalid characters */
bb1584c8
RS
716 if (strpbrk (name, "*?|<>\""))
717 return 0;
718
76b3903d
GV
719 dir_handle = FindFirstFile (name, &find_data);
720 if (dir_handle != INVALID_HANDLE_VALUE)
721 {
722 if ((len = strlen (find_data.cFileName)) < size)
723 memcpy (buf, find_data.cFileName, len + 1);
724 else
725 len = 0;
726 FindClose (dir_handle);
727 }
728 return len;
729}
730
731/* Get long name for file, if possible (assumed to be absolute). */
732BOOL
733w32_get_long_filename (char * name, char * buf, int size)
734{
735 char * o = buf;
736 char * p;
737 char * q;
738 char full[ MAX_PATH ];
739 int len;
740
741 len = strlen (name);
742 if (len >= MAX_PATH)
743 return FALSE;
744
745 /* Use local copy for destructive modification. */
746 memcpy (full, name, len+1);
747 unixtodos_filename (full);
748
749 /* Copy root part verbatim. */
750 len = parse_root (full, &p);
751 memcpy (o, full, len);
752 o += len;
4f8ac0b2 753 *o = '\0';
76b3903d
GV
754 size -= len;
755
4f8ac0b2 756 while (p != NULL && *p)
76b3903d
GV
757 {
758 q = p;
759 p = strchr (q, '\\');
760 if (p) *p = '\0';
761 len = get_long_basename (full, o, size);
762 if (len > 0)
763 {
764 o += len;
765 size -= len;
766 if (p != NULL)
767 {
768 *p++ = '\\';
769 if (size < 2)
770 return FALSE;
771 *o++ = '\\';
772 size--;
773 *o = '\0';
774 }
775 }
776 else
777 return FALSE;
778 }
76b3903d
GV
779
780 return TRUE;
781}
782
9d3355d1
GV
783int
784is_unc_volume (const char *filename)
785{
786 const char *ptr = filename;
787
788 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
789 return 0;
790
791 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
792 return 0;
793
794 return 1;
795}
76b3903d 796
95ed0025
RS
797/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
798
177c0ea7
JB
799int
800sigsetmask (int signal_mask)
801{
95ed0025
RS
802 return 0;
803}
804
177c0ea7
JB
805int
806sigmask (int sig)
807{
8f900f6e
AI
808 return 0;
809}
810
177c0ea7
JB
811int
812sigblock (int sig)
813{
95ed0025
RS
814 return 0;
815}
816
177c0ea7
JB
817int
818sigunblock (int sig)
819{
8f900f6e
AI
820 return 0;
821}
822
177c0ea7
JB
823int
824setpgrp (int pid, int gid)
825{
95ed0025
RS
826 return 0;
827}
828
177c0ea7
JB
829int
830alarm (int seconds)
831{
95ed0025
RS
832 return 0;
833}
834
177c0ea7
JB
835void
836unrequest_sigio (void)
837{
c6624584 838 return;
95ed0025
RS
839}
840
c6624584 841void
177c0ea7
JB
842request_sigio (void)
843{
c6624584 844 return;
95ed0025
RS
845}
846
480b0c5b 847#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
f332b293 848
177c0ea7 849LPBYTE
fbd6baed 850w32_get_resource (key, lpdwtype)
f332b293
GV
851 char *key;
852 LPDWORD lpdwtype;
853{
854 LPBYTE lpvalue;
855 HKEY hrootkey = NULL;
856 DWORD cbData;
857 BOOL ok = FALSE;
177c0ea7
JB
858
859 /* Check both the current user and the local machine to see if
f332b293 860 we have any resources. */
177c0ea7 861
f332b293
GV
862 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
863 {
864 lpvalue = NULL;
865
177c0ea7
JB
866 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
867 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
f332b293
GV
868 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
869 {
870 return (lpvalue);
871 }
872
873 if (lpvalue) xfree (lpvalue);
177c0ea7 874
f332b293 875 RegCloseKey (hrootkey);
177c0ea7
JB
876 }
877
f332b293
GV
878 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
879 {
880 lpvalue = NULL;
177c0ea7 881
76b3903d
GV
882 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
883 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
884 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
f332b293
GV
885 {
886 return (lpvalue);
887 }
177c0ea7 888
f332b293 889 if (lpvalue) xfree (lpvalue);
177c0ea7 890
f332b293 891 RegCloseKey (hrootkey);
177c0ea7
JB
892 }
893
f332b293
GV
894 return (NULL);
895}
896
75b08edb
GV
897char *get_emacs_configuration (void);
898extern Lisp_Object Vsystem_configuration;
899
f332b293 900void
aa7b87b0 901init_environment (char ** argv)
f332b293 902{
b3308d2e
KH
903 static const char * const tempdirs[] = {
904 "$TMPDIR", "$TEMP", "$TMP", "c:/"
905 };
906 int i;
907 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
908
909 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
910 temporary files and assume "/tmp" if $TMPDIR is unset, which
911 will break on DOS/Windows. Refuse to work if we cannot find
912 a directory, not even "c:/", usable for that purpose. */
913 for (i = 0; i < imax ; i++)
914 {
915 const char *tmp = tempdirs[i];
916
917 if (*tmp == '$')
918 tmp = getenv (tmp + 1);
919 /* Note that `access' can lie to us if the directory resides on a
920 read-only filesystem, like CD-ROM or a write-protected floppy.
921 The only way to be really sure is to actually create a file and
922 see if it succeeds. But I think that's too much to ask. */
a302c7ae 923 if (tmp && _access (tmp, D_OK) == 0)
b3308d2e
KH
924 {
925 char * var = alloca (strlen (tmp) + 8);
926 sprintf (var, "TMPDIR=%s", tmp);
aca583b2 927 _putenv (strdup (var));
b3308d2e
KH
928 break;
929 }
930 }
931 if (i >= imax)
932 cmd_error_internal
933 (Fcons (Qerror,
934 Fcons (build_string ("no usable temporary directories found!!"),
935 Qnil)),
936 "While setting TMPDIR: ");
937
ca149beb
AI
938 /* Check for environment variables and use registry settings if they
939 don't exist. Fallback on default values where applicable. */
f332b293 940 {
480b0c5b
GV
941 int i;
942 LPBYTE lpval;
943 DWORD dwType;
69fb0241 944 char locale_name[32];
f332b293 945
ca149beb
AI
946 static struct env_entry
947 {
948 char * name;
949 char * def_value;
177c0ea7 950 } env_vars[] =
ca149beb
AI
951 {
952 {"HOME", "C:/"},
953 {"PRELOAD_WINSOCK", NULL},
954 {"emacs_dir", "C:/emacs"},
cc14250a 955 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
ca149beb
AI
956 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
957 {"EMACSDATA", "%emacs_dir%/etc"},
958 {"EMACSPATH", "%emacs_dir%/bin"},
76b3903d 959 /* We no longer set INFOPATH because Info-default-directory-list
ca149beb
AI
960 is then ignored. */
961 /* {"INFOPATH", "%emacs_dir%/info"}, */
962 {"EMACSDOC", "%emacs_dir%/etc"},
69fb0241
JR
963 {"TERM", "cmd"},
964 {"LANG", NULL},
480b0c5b
GV
965 };
966
69fb0241
JR
967 /* Get default locale info and use it for LANG. */
968 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
969 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
970 locale_name, sizeof (locale_name)))
971 {
972 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
973 {
974 if (strcmp (env_vars[i].name, "LANG") == 0)
975 {
976 env_vars[i].def_value = locale_name;
977 break;
978 }
979 }
980 }
981
ca149beb
AI
982#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
983
984 /* Treat emacs_dir specially: set it unconditionally based on our
985 location, if it appears that we are running from the bin subdir
986 of a standard installation. */
987 {
988 char *p;
989 char modname[MAX_PATH];
990
991 if (!GetModuleFileName (NULL, modname, MAX_PATH))
992 abort ();
993 if ((p = strrchr (modname, '\\')) == NULL)
994 abort ();
995 *p = 0;
996
997 if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
998 {
999 char buf[SET_ENV_BUF_SIZE];
1000
1001 *p = 0;
1002 for (p = modname; *p; p++)
1003 if (*p == '\\') *p = '/';
177c0ea7 1004
ca149beb 1005 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
a302c7ae 1006 _putenv (strdup (buf));
ca149beb 1007 }
950090be
JR
1008 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1009
1010 /* FIXME: should use substring of get_emacs_configuration ().
1011 But I don't think the Windows build supports alpha, mips etc
1012 anymore, so have taken the easy option for now. */
1013 else if (p && stricmp (p, "\\i386") == 0)
1014 {
1015 *p = 0;
1016 p = strrchr (modname, '\\');
1017 if (p != NULL)
1018 {
1019 *p = 0;
1020 p = strrchr (modname, '\\');
1021 if (p && stricmp (p, "\\src") == 0)
1022 {
1023 char buf[SET_ENV_BUF_SIZE];
1024
1025 *p = 0;
1026 for (p = modname; *p; p++)
1027 if (*p == '\\') *p = '/';
1028
1029 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1030 _putenv (strdup (buf));
1031 }
1032 }
1033 }
ca149beb
AI
1034 }
1035
69fb0241 1036 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
f332b293 1037 {
ca149beb 1038 if (!getenv (env_vars[i].name))
480b0c5b 1039 {
ca149beb 1040 int dont_free = 0;
480b0c5b 1041
ca149beb
AI
1042 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL)
1043 {
1044 lpval = env_vars[i].def_value;
1045 dwType = REG_EXPAND_SZ;
1046 dont_free = 1;
480b0c5b 1047 }
ca149beb
AI
1048
1049 if (lpval)
480b0c5b 1050 {
ca149beb
AI
1051 if (dwType == REG_EXPAND_SZ)
1052 {
1053 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1054
1055 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
1056 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name, buf1);
a302c7ae 1057 _putenv (strdup (buf2));
ca149beb
AI
1058 }
1059 else if (dwType == REG_SZ)
1060 {
1061 char buf[SET_ENV_BUF_SIZE];
177c0ea7 1062
ca149beb 1063 _snprintf (buf, sizeof(buf)-1, "%s=%s", env_vars[i].name, lpval);
a302c7ae 1064 _putenv (strdup (buf));
ca149beb 1065 }
f332b293 1066
ca149beb
AI
1067 if (!dont_free)
1068 xfree (lpval);
1069 }
480b0c5b
GV
1070 }
1071 }
1072 }
1073
75b08edb
GV
1074 /* Rebuild system configuration to reflect invoking system. */
1075 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1076
76b3903d
GV
1077 /* Another special case: on NT, the PATH variable is actually named
1078 "Path" although cmd.exe (perhaps NT itself) arranges for
1079 environment variable lookup and setting to be case insensitive.
1080 However, Emacs assumes a fully case sensitive environment, so we
1081 need to change "Path" to "PATH" to match the expectations of
1082 various elisp packages. We do this by the sneaky method of
1083 modifying the string in the C runtime environ entry.
1084
1085 The same applies to COMSPEC. */
1086 {
1087 char ** envp;
1088
1089 for (envp = environ; *envp; envp++)
1090 if (_strnicmp (*envp, "PATH=", 5) == 0)
1091 memcpy (*envp, "PATH=", 5);
1092 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1093 memcpy (*envp, "COMSPEC=", 8);
1094 }
1095
1096 /* Remember the initial working directory for getwd, then make the
1097 real wd be the location of emacs.exe to avoid conflicts when
1098 renaming or deleting directories. (We also don't call chdir when
1099 running subprocesses for the same reason.) */
1100 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1101 abort ();
1102
1103 {
1104 char *p;
aa7b87b0 1105 static char modname[MAX_PATH];
76b3903d
GV
1106
1107 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1108 abort ();
1109 if ((p = strrchr (modname, '\\')) == NULL)
1110 abort ();
1111 *p = 0;
1112
1113 SetCurrentDirectory (modname);
aa7b87b0
AI
1114
1115 /* Ensure argv[0] has the full path to Emacs. */
1116 *p = '\\';
1117 argv[0] = modname;
76b3903d
GV
1118 }
1119
20af4831
JR
1120 /* Determine if there is a middle mouse button, to allow parse_button
1121 to decide whether right mouse events should be mouse-2 or
1122 mouse-3. */
e0c181dd 1123 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
20af4831 1124
480b0c5b
GV
1125 init_user_info ();
1126}
1127
bf794306
EZ
1128char *
1129emacs_root_dir (void)
1130{
1131 static char root_dir[FILENAME_MAX];
1132 const char *p;
1133
1134 p = getenv ("emacs_dir");
1135 if (p == NULL)
1136 abort ();
1137 strcpy (root_dir, p);
1138 root_dir[parse_root (root_dir, NULL)] = '\0';
1139 dostounix_filename (root_dir);
1140 return root_dir;
1141}
1142
480b0c5b
GV
1143/* We don't have scripts to automatically determine the system configuration
1144 for Emacs before it's compiled, and we don't want to have to make the
1145 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1146 routine. */
1147
480b0c5b
GV
1148char *
1149get_emacs_configuration (void)
1150{
1151 char *arch, *oem, *os;
c5247da2 1152 int build_num;
a302c7ae 1153 static char configuration_buffer[32];
480b0c5b
GV
1154
1155 /* Determine the processor type. */
177c0ea7 1156 switch (get_processor_type ())
480b0c5b
GV
1157 {
1158
1159#ifdef PROCESSOR_INTEL_386
1160 case PROCESSOR_INTEL_386:
1161 case PROCESSOR_INTEL_486:
1162 case PROCESSOR_INTEL_PENTIUM:
1163 arch = "i386";
1164 break;
1165#endif
1166
1167#ifdef PROCESSOR_INTEL_860
1168 case PROCESSOR_INTEL_860:
1169 arch = "i860";
1170 break;
1171#endif
1172
1173#ifdef PROCESSOR_MIPS_R2000
1174 case PROCESSOR_MIPS_R2000:
1175 case PROCESSOR_MIPS_R3000:
1176 case PROCESSOR_MIPS_R4000:
1177 arch = "mips";
1178 break;
1179#endif
1180
1181#ifdef PROCESSOR_ALPHA_21064
1182 case PROCESSOR_ALPHA_21064:
1183 arch = "alpha";
1184 break;
1185#endif
1186
1187 default:
1188 arch = "unknown";
1189 break;
f332b293 1190 }
480b0c5b 1191
a302c7ae
AI
1192 /* Use the OEM field to reflect the compiler/library combination. */
1193#ifdef _MSC_VER
1194#define COMPILER_NAME "msvc"
1195#else
1196#ifdef __GNUC__
1197#define COMPILER_NAME "mingw"
1198#else
1199#define COMPILER_NAME "unknown"
1200#endif
1201#endif
1202 oem = COMPILER_NAME;
480b0c5b 1203
c5247da2
GV
1204 switch (osinfo_cache.dwPlatformId) {
1205 case VER_PLATFORM_WIN32_NT:
1206 os = "nt";
1207 build_num = osinfo_cache.dwBuildNumber;
1208 break;
1209 case VER_PLATFORM_WIN32_WINDOWS:
1210 if (osinfo_cache.dwMinorVersion == 0) {
1211 os = "windows95";
1212 } else {
1213 os = "windows98";
1214 }
1215 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1216 break;
1217 case VER_PLATFORM_WIN32s:
1218 /* Not supported, should not happen. */
1219 os = "windows32s";
1220 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1221 break;
1222 default:
1223 os = "unknown";
1224 build_num = 0;
1225 break;
1226 }
1227
1228 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1229 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1230 get_w32_major_version (), get_w32_minor_version (), build_num);
1231 } else {
1232 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1233 }
480b0c5b 1234
480b0c5b 1235 return configuration_buffer;
f332b293
GV
1236}
1237
a302c7ae
AI
1238char *
1239get_emacs_configuration_options (void)
1240{
1241 static char options_buffer[256];
1242
1243/* Work out the effective configure options for this build. */
1244#ifdef _MSC_VER
1245#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1246#else
1247#ifdef __GNUC__
1248#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1249#else
1250#define COMPILER_VERSION ""
1251#endif
1252#endif
1253
1254 sprintf (options_buffer, COMPILER_VERSION);
1255#ifdef EMACSDEBUG
1256 strcat (options_buffer, " --no-opt");
1257#endif
1258#ifdef USER_CFLAGS
1259 strcat (options_buffer, " --cflags");
1260 strcat (options_buffer, USER_CFLAGS);
1261#endif
1262#ifdef USER_LDFLAGS
1263 strcat (options_buffer, " --ldflags");
1264 strcat (options_buffer, USER_LDFLAGS);
1265#endif
1266 return options_buffer;
1267}
1268
1269
35f0d482
KH
1270#include <sys/timeb.h>
1271
1272/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
177c0ea7 1273void
35f0d482
KH
1274gettimeofday (struct timeval *tv, struct timezone *tz)
1275{
a302c7ae 1276 struct timeb tb;
35f0d482
KH
1277 _ftime (&tb);
1278
1279 tv->tv_sec = tb.time;
1280 tv->tv_usec = tb.millitm * 1000L;
177c0ea7 1281 if (tz)
35f0d482
KH
1282 {
1283 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1284 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1285 }
1286}
35f0d482 1287
480b0c5b 1288/* ------------------------------------------------------------------------- */
fbd6baed 1289/* IO support and wrapper functions for W32 API. */
480b0c5b 1290/* ------------------------------------------------------------------------- */
95ed0025 1291
480b0c5b 1292/* Place a wrapper around the MSVC version of ctime. It returns NULL
177c0ea7 1293 on network directories, so we handle that case here.
480b0c5b
GV
1294 (Ulrich Leodolter, 1/11/95). */
1295char *
1296sys_ctime (const time_t *t)
1297{
1298 char *str = (char *) ctime (t);
1299 return (str ? str : "Sun Jan 01 00:00:00 1970");
1300}
1301
1302/* Emulate sleep...we could have done this with a define, but that
1303 would necessitate including windows.h in the files that used it.
1304 This is much easier. */
1305void
1306sys_sleep (int seconds)
1307{
1308 Sleep (seconds * 1000);
1309}
1310
76b3903d 1311/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
1312extern int __cdecl _set_osfhnd (int fd, long h);
1313extern int __cdecl _free_osfhnd (int fd);
1314
1315/* parallel array of private info on file handles */
1316filedesc fd_info [ MAXDESC ];
1317
76b3903d
GV
1318typedef struct volume_info_data {
1319 struct volume_info_data * next;
1320
1321 /* time when info was obtained */
1322 DWORD timestamp;
1323
1324 /* actual volume info */
1325 char * root_dir;
480b0c5b
GV
1326 DWORD serialnum;
1327 DWORD maxcomp;
1328 DWORD flags;
76b3903d
GV
1329 char * name;
1330 char * type;
1331} volume_info_data;
1332
1333/* Global referenced by various functions. */
1334static volume_info_data volume_info;
1335
1336/* Vector to indicate which drives are local and fixed (for which cached
1337 data never expires). */
1338static BOOL fixed_drives[26];
1339
1340/* Consider cached volume information to be stale if older than 10s,
1341 at least for non-local drives. Info for fixed drives is never stale. */
1342#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1343#define VOLINFO_STILL_VALID( root_dir, info ) \
1344 ( ( isalpha (root_dir[0]) && \
1345 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1346 || GetTickCount () - info->timestamp < 10000 )
1347
1348/* Cache support functions. */
1349
1350/* Simple linked list with linear search is sufficient. */
1351static volume_info_data *volume_cache = NULL;
1352
1353static volume_info_data *
1354lookup_volume_info (char * root_dir)
1355{
1356 volume_info_data * info;
1357
1358 for (info = volume_cache; info; info = info->next)
1359 if (stricmp (info->root_dir, root_dir) == 0)
1360 break;
1361 return info;
1362}
1363
1364static void
1365add_volume_info (char * root_dir, volume_info_data * info)
1366{
a302c7ae 1367 info->root_dir = xstrdup (root_dir);
76b3903d
GV
1368 info->next = volume_cache;
1369 volume_cache = info;
1370}
1371
1372
1373/* Wrapper for GetVolumeInformation, which uses caching to avoid
1374 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1375 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1376volume_info_data *
1377GetCachedVolumeInformation (char * root_dir)
1378{
1379 volume_info_data * info;
1380 char default_root[ MAX_PATH ];
1381
1382 /* NULL for root_dir means use root from current directory. */
1383 if (root_dir == NULL)
1384 {
1385 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1386 return NULL;
1387 parse_root (default_root, &root_dir);
1388 *root_dir = 0;
1389 root_dir = default_root;
1390 }
1391
1392 /* Local fixed drives can be cached permanently. Removable drives
1393 cannot be cached permanently, since the volume name and serial
1394 number (if nothing else) can change. Remote drives should be
1395 treated as if they are removable, since there is no sure way to
1396 tell whether they are or not. Also, the UNC association of drive
1397 letters mapped to remote volumes can be changed at any time (even
1398 by other processes) without notice.
177c0ea7 1399
76b3903d
GV
1400 As a compromise, so we can benefit from caching info for remote
1401 volumes, we use a simple expiry mechanism to invalidate cache
1402 entries that are more than ten seconds old. */
1403
1404#if 0
1405 /* No point doing this, because WNetGetConnection is even slower than
1406 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1407 GetDriveType is about the only call of this type which does not
1408 involve network access, and so is extremely quick). */
1409
1410 /* Map drive letter to UNC if remote. */
1411 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1412 {
1413 char remote_name[ 256 ];
1414 char drive[3] = { root_dir[0], ':' };
1415
1416 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1417 == NO_ERROR)
1418 /* do something */ ;
1419 }
1420#endif
1421
1422 info = lookup_volume_info (root_dir);
1423
1424 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1425 {
1426 char name[ 256 ];
1427 DWORD serialnum;
1428 DWORD maxcomp;
1429 DWORD flags;
1430 char type[ 256 ];
1431
1432 /* Info is not cached, or is stale. */
1433 if (!GetVolumeInformation (root_dir,
1434 name, sizeof (name),
1435 &serialnum,
1436 &maxcomp,
1437 &flags,
1438 type, sizeof (type)))
1439 return NULL;
1440
1441 /* Cache the volume information for future use, overwriting existing
1442 entry if present. */
1443 if (info == NULL)
1444 {
1445 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1446 add_volume_info (root_dir, info);
1447 }
1448 else
1449 {
a302c7ae
AI
1450 xfree (info->name);
1451 xfree (info->type);
76b3903d
GV
1452 }
1453
a302c7ae 1454 info->name = xstrdup (name);
76b3903d
GV
1455 info->serialnum = serialnum;
1456 info->maxcomp = maxcomp;
1457 info->flags = flags;
a302c7ae 1458 info->type = xstrdup (type);
76b3903d
GV
1459 info->timestamp = GetTickCount ();
1460 }
1461
1462 return info;
1463}
480b0c5b
GV
1464
1465/* Get information on the volume where name is held; set path pointer to
1466 start of pathname in name (past UNC header\volume header if present). */
1467int
1468get_volume_info (const char * name, const char ** pPath)
95ed0025 1469{
480b0c5b
GV
1470 char temp[MAX_PATH];
1471 char *rootname = NULL; /* default to current volume */
76b3903d 1472 volume_info_data * info;
480b0c5b
GV
1473
1474 if (name == NULL)
1475 return FALSE;
1476
1477 /* find the root name of the volume if given */
1478 if (isalpha (name[0]) && name[1] == ':')
1479 {
1480 rootname = temp;
1481 temp[0] = *name++;
1482 temp[1] = *name++;
1483 temp[2] = '\\';
1484 temp[3] = 0;
1485 }
1486 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1487 {
480b0c5b
GV
1488 char *str = temp;
1489 int slashes = 4;
1490 rootname = temp;
1491 do
1492 {
1493 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1494 break;
1495 *str++ = *name++;
1496 }
1497 while ( *name );
1498
480b0c5b
GV
1499 *str++ = '\\';
1500 *str = 0;
95ed0025 1501 }
480b0c5b
GV
1502
1503 if (pPath)
1504 *pPath = name;
177c0ea7 1505
76b3903d
GV
1506 info = GetCachedVolumeInformation (rootname);
1507 if (info != NULL)
95ed0025 1508 {
76b3903d
GV
1509 /* Set global referenced by other functions. */
1510 volume_info = *info;
480b0c5b 1511 return TRUE;
95ed0025 1512 }
480b0c5b
GV
1513 return FALSE;
1514}
1515
1516/* Determine if volume is FAT format (ie. only supports short 8.3
1517 names); also set path pointer to start of pathname in name. */
1518int
1519is_fat_volume (const char * name, const char ** pPath)
1520{
1521 if (get_volume_info (name, pPath))
1522 return (volume_info.maxcomp == 12);
1523 return FALSE;
1524}
1525
1526/* Map filename to a legal 8.3 name if necessary. */
1527const char *
fbd6baed 1528map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1529{
1530 static char shortname[MAX_PATH];
1531 char * str = shortname;
1532 char c;
480b0c5b 1533 char * path;
76b3903d 1534 const char * save_name = name;
480b0c5b 1535
ca149beb
AI
1536 if (strlen (name) >= MAX_PATH)
1537 {
1538 /* Return a filename which will cause callers to fail. */
1539 strcpy (shortname, "?");
1540 return shortname;
1541 }
1542
a302c7ae 1543 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
95ed0025 1544 {
480b0c5b
GV
1545 register int left = 8; /* maximum number of chars in part */
1546 register int extn = 0; /* extension added? */
1547 register int dots = 2; /* maximum number of dots allowed */
1548
1549 while (name < path)
1550 *str++ = *name++; /* skip past UNC header */
1551
1552 while ((c = *name++))
1553 {
1554 switch ( c )
1555 {
1556 case '\\':
1557 case '/':
1558 *str++ = '\\';
1559 extn = 0; /* reset extension flags */
1560 dots = 2; /* max 2 dots */
1561 left = 8; /* max length 8 for main part */
1562 break;
1563 case ':':
1564 *str++ = ':';
1565 extn = 0; /* reset extension flags */
1566 dots = 2; /* max 2 dots */
1567 left = 8; /* max length 8 for main part */
1568 break;
1569 case '.':
1570 if ( dots )
1571 {
1572 /* Convert path components of the form .xxx to _xxx,
1573 but leave . and .. as they are. This allows .emacs
1574 to be read as _emacs, for example. */
1575
1576 if (! *name ||
1577 *name == '.' ||
1578 IS_DIRECTORY_SEP (*name))
1579 {
1580 *str++ = '.';
1581 dots--;
1582 }
1583 else
1584 {
1585 *str++ = '_';
1586 left--;
1587 dots = 0;
1588 }
1589 }
1590 else if ( !extn )
1591 {
1592 *str++ = '.';
1593 extn = 1; /* we've got an extension */
1594 left = 3; /* 3 chars in extension */
1595 }
1596 else
1597 {
1598 /* any embedded dots after the first are converted to _ */
1599 *str++ = '_';
1600 }
1601 break;
1602 case '~':
1603 case '#': /* don't lose these, they're important */
1604 if ( ! left )
1605 str[-1] = c; /* replace last character of part */
1606 /* FALLTHRU */
1607 default:
1608 if ( left )
1609 {
1610 *str++ = tolower (c); /* map to lower case (looks nicer) */
1611 left--;
1612 dots = 0; /* started a path component */
1613 }
1614 break;
1615 }
1616 }
1617 *str = '\0';
fc85cb29
RS
1618 }
1619 else
1620 {
1621 strcpy (shortname, name);
1622 unixtodos_filename (shortname);
95ed0025 1623 }
480b0c5b
GV
1624
1625 if (pPath)
76b3903d 1626 *pPath = shortname + (path - save_name);
480b0c5b 1627
fc85cb29 1628 return shortname;
480b0c5b
GV
1629}
1630
b3308d2e
KH
1631static int
1632is_exec (const char * name)
1633{
1634 char * p = strrchr (name, '.');
1635 return
1636 (p != NULL
1637 && (stricmp (p, ".exe") == 0 ||
1638 stricmp (p, ".com") == 0 ||
1639 stricmp (p, ".bat") == 0 ||
1640 stricmp (p, ".cmd") == 0));
1641}
1642
177c0ea7 1643/* Emulate the Unix directory procedures opendir, closedir,
76b3903d
GV
1644 and readdir. We can't use the procedures supplied in sysdep.c,
1645 so we provide them here. */
1646
1647struct direct dir_static; /* simulated directory contents */
1648static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1649static int dir_is_fat;
1650static char dir_pathname[MAXPATHLEN+1];
1651static WIN32_FIND_DATA dir_find_data;
1652
9d3355d1
GV
1653/* Support shares on a network resource as subdirectories of a read-only
1654 root directory. */
1655static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
e0c181dd 1656HANDLE open_unc_volume (const char *);
9d3355d1
GV
1657char *read_unc_volume (HANDLE, char *, int);
1658void close_unc_volume (HANDLE);
1659
76b3903d
GV
1660DIR *
1661opendir (char *filename)
1662{
1663 DIR *dirp;
1664
1665 /* Opening is done by FindFirstFile. However, a read is inherent to
1666 this operation, so we defer the open until read time. */
1667
76b3903d
GV
1668 if (dir_find_handle != INVALID_HANDLE_VALUE)
1669 return NULL;
9d3355d1
GV
1670 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1671 return NULL;
1672
1673 if (is_unc_volume (filename))
1674 {
1675 wnet_enum_handle = open_unc_volume (filename);
1676 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1677 return NULL;
1678 }
1679
1680 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1681 return NULL;
76b3903d
GV
1682
1683 dirp->dd_fd = 0;
1684 dirp->dd_loc = 0;
1685 dirp->dd_size = 0;
1686
1687 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1688 dir_pathname[MAXPATHLEN] = '\0';
1689 dir_is_fat = is_fat_volume (filename, NULL);
1690
1691 return dirp;
1692}
1693
1694void
1695closedir (DIR *dirp)
1696{
1697 /* If we have a find-handle open, close it. */
1698 if (dir_find_handle != INVALID_HANDLE_VALUE)
1699 {
1700 FindClose (dir_find_handle);
1701 dir_find_handle = INVALID_HANDLE_VALUE;
1702 }
9d3355d1
GV
1703 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1704 {
1705 close_unc_volume (wnet_enum_handle);
1706 wnet_enum_handle = INVALID_HANDLE_VALUE;
1707 }
76b3903d
GV
1708 xfree ((char *) dirp);
1709}
1710
1711struct direct *
1712readdir (DIR *dirp)
1713{
9d3355d1
GV
1714 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1715 {
177c0ea7
JB
1716 if (!read_unc_volume (wnet_enum_handle,
1717 dir_find_data.cFileName,
9d3355d1
GV
1718 MAX_PATH))
1719 return NULL;
1720 }
76b3903d 1721 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 1722 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
1723 {
1724 char filename[MAXNAMLEN + 3];
1725 int ln;
1726
1727 strcpy (filename, dir_pathname);
1728 ln = strlen (filename) - 1;
1729 if (!IS_DIRECTORY_SEP (filename[ln]))
1730 strcat (filename, "\\");
1731 strcat (filename, "*");
1732
1733 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1734
1735 if (dir_find_handle == INVALID_HANDLE_VALUE)
1736 return NULL;
1737 }
1738 else
1739 {
1740 if (!FindNextFile (dir_find_handle, &dir_find_data))
1741 return NULL;
1742 }
177c0ea7 1743
76b3903d
GV
1744 /* Emacs never uses this value, so don't bother making it match
1745 value returned by stat(). */
1746 dir_static.d_ino = 1;
177c0ea7 1747
76b3903d
GV
1748 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1749 dir_static.d_namlen - dir_static.d_namlen % 4;
177c0ea7 1750
76b3903d
GV
1751 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1752 strcpy (dir_static.d_name, dir_find_data.cFileName);
1753 if (dir_is_fat)
1754 _strlwr (dir_static.d_name);
1755 else if (!NILP (Vw32_downcase_file_names))
1756 {
1757 register char *p;
1758 for (p = dir_static.d_name; *p; p++)
1759 if (*p >= 'a' && *p <= 'z')
1760 break;
1761 if (!*p)
1762 _strlwr (dir_static.d_name);
1763 }
177c0ea7 1764
76b3903d
GV
1765 return &dir_static;
1766}
1767
9d3355d1 1768HANDLE
e0c181dd 1769open_unc_volume (const char *path)
9d3355d1 1770{
177c0ea7 1771 NETRESOURCE nr;
9d3355d1
GV
1772 HANDLE henum;
1773 int result;
1774
177c0ea7
JB
1775 nr.dwScope = RESOURCE_GLOBALNET;
1776 nr.dwType = RESOURCETYPE_DISK;
1777 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1778 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1779 nr.lpLocalName = NULL;
9d3355d1 1780 nr.lpRemoteName = map_w32_filename (path, NULL);
177c0ea7
JB
1781 nr.lpComment = NULL;
1782 nr.lpProvider = NULL;
9d3355d1 1783
177c0ea7 1784 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
9d3355d1
GV
1785 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1786
1787 if (result == NO_ERROR)
1788 return henum;
1789 else
1790 return INVALID_HANDLE_VALUE;
1791}
1792
1793char *
1794read_unc_volume (HANDLE henum, char *readbuf, int size)
1795{
a302c7ae 1796 DWORD count;
9d3355d1 1797 int result;
a302c7ae 1798 DWORD bufsize = 512;
9d3355d1
GV
1799 char *buffer;
1800 char *ptr;
1801
1802 count = 1;
1803 buffer = alloca (bufsize);
1804 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1805 if (result != NO_ERROR)
1806 return NULL;
1807
1808 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1809 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1810 ptr += 2;
1811 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1812 ptr++;
1813
1814 strncpy (readbuf, ptr, size);
1815 return readbuf;
1816}
1817
1818void
1819close_unc_volume (HANDLE henum)
1820{
1821 if (henum != INVALID_HANDLE_VALUE)
1822 WNetCloseEnum (henum);
1823}
1824
1825DWORD
e0c181dd 1826unc_volume_file_attributes (const char *path)
9d3355d1
GV
1827{
1828 HANDLE henum;
1829 DWORD attrs;
1830
1831 henum = open_unc_volume (path);
1832 if (henum == INVALID_HANDLE_VALUE)
1833 return -1;
1834
1835 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
1836
1837 close_unc_volume (henum);
1838
1839 return attrs;
1840}
1841
480b0c5b
GV
1842
1843/* Shadow some MSVC runtime functions to map requests for long filenames
1844 to reasonable short names if necessary. This was originally added to
177c0ea7 1845 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
480b0c5b
GV
1846 long file names. */
1847
1848int
1849sys_access (const char * path, int mode)
1850{
b3308d2e
KH
1851 DWORD attributes;
1852
1853 /* MSVC implementation doesn't recognize D_OK. */
1854 path = map_w32_filename (path, NULL);
9d3355d1
GV
1855 if (is_unc_volume (path))
1856 {
1857 attributes = unc_volume_file_attributes (path);
1858 if (attributes == -1) {
1859 errno = EACCES;
1860 return -1;
1861 }
1862 }
1863 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
1864 {
1865 /* Should try mapping GetLastError to errno; for now just indicate
1866 that path doesn't exist. */
1867 errno = EACCES;
1868 return -1;
1869 }
1870 if ((mode & X_OK) != 0 && !is_exec (path))
1871 {
1872 errno = EACCES;
1873 return -1;
1874 }
1875 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
1876 {
1877 errno = EACCES;
1878 return -1;
1879 }
1880 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
1881 {
1882 errno = EACCES;
1883 return -1;
1884 }
1885 return 0;
480b0c5b
GV
1886}
1887
1888int
1889sys_chdir (const char * path)
1890{
fbd6baed 1891 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
1892}
1893
1894int
1895sys_chmod (const char * path, int mode)
1896{
fbd6baed 1897 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1898}
1899
1900int
1901sys_creat (const char * path, int mode)
1902{
fbd6baed 1903 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1904}
1905
1906FILE *
1907sys_fopen(const char * path, const char * mode)
1908{
1909 int fd;
1910 int oflag;
1911 const char * mode_save = mode;
1912
1913 /* Force all file handles to be non-inheritable. This is necessary to
1914 ensure child processes don't unwittingly inherit handles that might
1915 prevent future file access. */
1916
1917 if (mode[0] == 'r')
1918 oflag = O_RDONLY;
1919 else if (mode[0] == 'w' || mode[0] == 'a')
1920 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 1921 else
480b0c5b
GV
1922 return NULL;
1923
1924 /* Only do simplistic option parsing. */
1925 while (*++mode)
1926 if (mode[0] == '+')
1927 {
1928 oflag &= ~(O_RDONLY | O_WRONLY);
1929 oflag |= O_RDWR;
1930 }
1931 else if (mode[0] == 'b')
1932 {
1933 oflag &= ~O_TEXT;
1934 oflag |= O_BINARY;
1935 }
1936 else if (mode[0] == 't')
1937 {
1938 oflag &= ~O_BINARY;
1939 oflag |= O_TEXT;
1940 }
1941 else break;
1942
fbd6baed 1943 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
1944 if (fd < 0)
1945 return NULL;
1946
76b3903d 1947 return _fdopen (fd, mode_save);
95ed0025 1948}
480b0c5b 1949
76b3903d 1950/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 1951int
76b3903d 1952sys_link (const char * old, const char * new)
480b0c5b 1953{
76b3903d
GV
1954 HANDLE fileh;
1955 int result = -1;
1956 char oldname[MAX_PATH], newname[MAX_PATH];
1957
1958 if (old == NULL || new == NULL)
1959 {
1960 errno = ENOENT;
1961 return -1;
1962 }
1963
1964 strcpy (oldname, map_w32_filename (old, NULL));
1965 strcpy (newname, map_w32_filename (new, NULL));
1966
1967 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
1968 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1969 if (fileh != INVALID_HANDLE_VALUE)
1970 {
1971 int wlen;
1972
1973 /* Confusingly, the "alternate" stream name field does not apply
1974 when restoring a hard link, and instead contains the actual
1975 stream data for the link (ie. the name of the link to create).
1976 The WIN32_STREAM_ID structure before the cStreamName field is
1977 the stream header, which is then immediately followed by the
1978 stream data. */
1979
1980 struct {
1981 WIN32_STREAM_ID wid;
1982 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
1983 } data;
1984
1985 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
1986 data.wid.cStreamName, MAX_PATH);
1987 if (wlen > 0)
1988 {
1989 LPVOID context = NULL;
1990 DWORD wbytes = 0;
1991
1992 data.wid.dwStreamId = BACKUP_LINK;
1993 data.wid.dwStreamAttributes = 0;
1994 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
1995 data.wid.Size.HighPart = 0;
1996 data.wid.dwStreamNameSize = 0;
1997
1998 if (BackupWrite (fileh, (LPBYTE)&data,
1999 offsetof (WIN32_STREAM_ID, cStreamName)
2000 + data.wid.Size.LowPart,
2001 &wbytes, FALSE, FALSE, &context)
2002 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2003 {
2004 /* succeeded */
2005 result = 0;
2006 }
2007 else
2008 {
2009 /* Should try mapping GetLastError to errno; for now just
2010 indicate a general error (eg. links not supported). */
2011 errno = EINVAL; // perhaps EMLINK?
2012 }
2013 }
2014
2015 CloseHandle (fileh);
2016 }
2017 else
2018 errno = ENOENT;
2019
2020 return result;
480b0c5b
GV
2021}
2022
2023int
2024sys_mkdir (const char * path)
2025{
fbd6baed 2026 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
2027}
2028
9d1778b1
RS
2029/* Because of long name mapping issues, we need to implement this
2030 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2031 a unique name, instead of setting the input template to an empty
2032 string.
2033
2034 Standard algorithm seems to be use pid or tid with a letter on the
2035 front (in place of the 6 X's) and cycle through the letters to find a
2036 unique name. We extend that to allow any reasonable character as the
2037 first of the 6 X's. */
480b0c5b
GV
2038char *
2039sys_mktemp (char * template)
2040{
9d1778b1
RS
2041 char * p;
2042 int i;
2043 unsigned uid = GetCurrentThreadId ();
2044 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2045
2046 if (template == NULL)
2047 return NULL;
2048 p = template + strlen (template);
2049 i = 5;
2050 /* replace up to the last 5 X's with uid in decimal */
2051 while (--p >= template && p[0] == 'X' && --i >= 0)
2052 {
2053 p[0] = '0' + uid % 10;
2054 uid /= 10;
2055 }
2056
2057 if (i < 0 && p[0] == 'X')
2058 {
2059 i = 0;
2060 do
2061 {
2062 int save_errno = errno;
2063 p[0] = first_char[i];
2064 if (sys_access (template, 0) < 0)
2065 {
2066 errno = save_errno;
2067 return template;
2068 }
2069 }
2070 while (++i < sizeof (first_char));
2071 }
2072
2073 /* Template is badly formed or else we can't generate a unique name,
2074 so return empty string */
2075 template[0] = 0;
2076 return template;
480b0c5b
GV
2077}
2078
2079int
2080sys_open (const char * path, int oflag, int mode)
2081{
302f0b29
GM
2082 const char* mpath = map_w32_filename (path, NULL);
2083 /* Try to open file without _O_CREAT, to be able to write to hidden
2084 and system files. Force all file handles to be
2085 non-inheritable. */
2086 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2087 if (res >= 0)
2088 return res;
2089 return _open (mpath, oflag | _O_NOINHERIT, mode);
480b0c5b
GV
2090}
2091
2092int
2093sys_rename (const char * oldname, const char * newname)
2094{
cfb5e855 2095 BOOL result;
b3308d2e 2096 char temp[MAX_PATH];
480b0c5b 2097
e9e23e23 2098 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
2099 alias in a number of circumstances (it is not easy to predict when
2100 just by looking at oldname and newname, unfortunately). In these
2101 cases, renaming through a temporary name avoids the problem.
2102
e9e23e23 2103 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
2104 newname is uppercase fails (the final long name ends up in
2105 lowercase, although the short alias might be uppercase) UNLESS the
2106 long temp name is not 8.3.
2107
e9e23e23 2108 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 2109 the temp name has a long extension to ensure correct renaming. */
480b0c5b 2110
fbd6baed 2111 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 2112
76b3903d 2113 if (os_subtype == OS_WIN95)
480b0c5b 2114 {
b3308d2e 2115 char * o;
480b0c5b 2116 char * p;
b3308d2e
KH
2117 int i = 0;
2118
2119 oldname = map_w32_filename (oldname, NULL);
2120 if (o = strrchr (oldname, '\\'))
2121 o++;
2122 else
2123 o = (char *) oldname;
480b0c5b 2124
480b0c5b
GV
2125 if (p = strrchr (temp, '\\'))
2126 p++;
2127 else
2128 p = temp;
b3308d2e
KH
2129
2130 do
2131 {
2132 /* Force temp name to require a manufactured 8.3 alias - this
2133 seems to make the second rename work properly. */
f313ee82 2134 sprintf (p, "_.%s.%u", o, i);
b3308d2e 2135 i++;
58f0cb7e 2136 result = rename (oldname, temp);
b3308d2e
KH
2137 }
2138 /* This loop must surely terminate! */
cfb5e855 2139 while (result < 0 && errno == EEXIST);
58f0cb7e 2140 if (result < 0)
480b0c5b
GV
2141 return -1;
2142 }
2143
2144 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 2145 (at least if it is a file; don't do this for directories).
76b3903d 2146
b3308d2e
KH
2147 Since we mustn't do this if we are just changing the case of the
2148 file name (we would end up deleting the file we are trying to
2149 rename!), we let rename detect if the destination file already
2150 exists - that way we avoid the possible pitfalls of trying to
2151 determine ourselves whether two names really refer to the same
2152 file, which is not always possible in the general case. (Consider
2153 all the permutations of shared or subst'd drives, etc.) */
2154
2155 newname = map_w32_filename (newname, NULL);
eb9ea53f 2156 result = rename (temp, newname);
b3308d2e
KH
2157
2158 if (result < 0
cfb5e855 2159 && errno == EEXIST
b3308d2e
KH
2160 && _chmod (newname, 0666) == 0
2161 && _unlink (newname) == 0)
2162 result = rename (temp, newname);
480b0c5b 2163
eb9ea53f 2164 return result;
480b0c5b
GV
2165}
2166
2167int
2168sys_rmdir (const char * path)
2169{
fbd6baed 2170 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
2171}
2172
2173int
2174sys_unlink (const char * path)
2175{
16bb7578
GV
2176 path = map_w32_filename (path, NULL);
2177
2178 /* On Unix, unlink works without write permission. */
2179 _chmod (path, 0666);
2180 return _unlink (path);
480b0c5b
GV
2181}
2182
2183static FILETIME utc_base_ft;
2184static long double utc_base;
2185static int init = 0;
2186
2187static time_t
2188convert_time (FILETIME ft)
2189{
2190 long double ret;
2191
2192 if (!init)
2193 {
2194 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2195 SYSTEMTIME st;
2196
2197 st.wYear = 1970;
2198 st.wMonth = 1;
2199 st.wDay = 1;
2200 st.wHour = 0;
2201 st.wMinute = 0;
2202 st.wSecond = 0;
2203 st.wMilliseconds = 0;
2204
2205 SystemTimeToFileTime (&st, &utc_base_ft);
2206 utc_base = (long double) utc_base_ft.dwHighDateTime
2207 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2208 init = 1;
2209 }
2210
2211 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2212 return 0;
2213
2214 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
2215 ret -= utc_base;
2216 return (time_t) (ret * 1e-7);
2217}
2218
480b0c5b
GV
2219void
2220convert_from_time_t (time_t time, FILETIME * pft)
2221{
2222 long double tmp;
2223
2224 if (!init)
2225 {
2226 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2227 SYSTEMTIME st;
2228
2229 st.wYear = 1970;
2230 st.wMonth = 1;
2231 st.wDay = 1;
2232 st.wHour = 0;
2233 st.wMinute = 0;
2234 st.wSecond = 0;
2235 st.wMilliseconds = 0;
2236
2237 SystemTimeToFileTime (&st, &utc_base_ft);
2238 utc_base = (long double) utc_base_ft.dwHighDateTime
2239 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2240 init = 1;
2241 }
2242
2243 /* time in 100ns units since 1-Jan-1601 */
2244 tmp = (long double) time * 1e7 + utc_base;
2245 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 2246 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 2247}
480b0c5b 2248
76b3903d
GV
2249#if 0
2250/* No reason to keep this; faking inode values either by hashing or even
2251 using the file index from GetInformationByHandle, is not perfect and
2252 so by default Emacs doesn't use the inode values on Windows.
2253 Instead, we now determine file-truename correctly (except for
2254 possible drive aliasing etc). */
2255
2256/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 2257static unsigned
76b3903d 2258hashval (const unsigned char * str)
480b0c5b
GV
2259{
2260 unsigned h = 0;
480b0c5b
GV
2261 while (*str)
2262 {
2263 h = (h << 4) + *str++;
76b3903d 2264 h ^= (h >> 28);
480b0c5b
GV
2265 }
2266 return h;
2267}
2268
2269/* Return the hash value of the canonical pathname, excluding the
2270 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 2271static DWORD
480b0c5b
GV
2272generate_inode_val (const char * name)
2273{
2274 char fullname[ MAX_PATH ];
2275 char * p;
2276 unsigned hash;
2277
76b3903d
GV
2278 /* Get the truly canonical filename, if it exists. (Note: this
2279 doesn't resolve aliasing due to subst commands, or recognise hard
2280 links. */
2281 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2282 abort ();
2283
2284 parse_root (fullname, &p);
fbd6baed 2285 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 2286 _strlwr (p);
76b3903d 2287 return hashval (p);
480b0c5b
GV
2288}
2289
76b3903d
GV
2290#endif
2291
480b0c5b
GV
2292/* MSVC stat function can't cope with UNC names and has other bugs, so
2293 replace it with our own. This also allows us to calculate consistent
2294 inode values without hacks in the main Emacs code. */
2295int
2296stat (const char * path, struct stat * buf)
2297{
eb9ea53f 2298 char *name, *r;
480b0c5b
GV
2299 WIN32_FIND_DATA wfd;
2300 HANDLE fh;
76b3903d 2301 DWORD fake_inode;
480b0c5b
GV
2302 int permission;
2303 int len;
2304 int rootdir = FALSE;
2305
2306 if (path == NULL || buf == NULL)
2307 {
2308 errno = EFAULT;
2309 return -1;
2310 }
2311
fbd6baed 2312 name = (char *) map_w32_filename (path, &path);
9ab8560d 2313 /* must be valid filename, no wild cards or other invalid characters */
bb1584c8 2314 if (strpbrk (name, "*?|<>\""))
480b0c5b
GV
2315 {
2316 errno = ENOENT;
2317 return -1;
2318 }
2319
eb9ea53f
GV
2320 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2321 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2322 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2323 {
2324 r[1] = r[2] = '\0';
2325 }
2326
480b0c5b
GV
2327 /* Remove trailing directory separator, unless name is the root
2328 directory of a drive or UNC volume in which case ensure there
2329 is a trailing separator. */
2330 len = strlen (name);
2331 rootdir = (path >= name + len - 1
2332 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2333 name = strcpy (alloca (len + 2), name);
2334
9d3355d1
GV
2335 if (is_unc_volume (name))
2336 {
2337 DWORD attrs = unc_volume_file_attributes (name);
2338
2339 if (attrs == -1)
2340 return -1;
2341
2342 memset (&wfd, 0, sizeof (wfd));
2343 wfd.dwFileAttributes = attrs;
2344 wfd.ftCreationTime = utc_base_ft;
2345 wfd.ftLastAccessTime = utc_base_ft;
2346 wfd.ftLastWriteTime = utc_base_ft;
2347 strcpy (wfd.cFileName, name);
2348 }
2349 else if (rootdir)
480b0c5b
GV
2350 {
2351 if (!IS_DIRECTORY_SEP (name[len-1]))
2352 strcat (name, "\\");
2353 if (GetDriveType (name) < 2)
2354 {
2355 errno = ENOENT;
2356 return -1;
2357 }
2358 memset (&wfd, 0, sizeof (wfd));
2359 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2360 wfd.ftCreationTime = utc_base_ft;
2361 wfd.ftLastAccessTime = utc_base_ft;
2362 wfd.ftLastWriteTime = utc_base_ft;
2363 strcpy (wfd.cFileName, name);
2364 }
2365 else
2366 {
2367 if (IS_DIRECTORY_SEP (name[len-1]))
2368 name[len - 1] = 0;
76b3903d
GV
2369
2370 /* (This is hacky, but helps when doing file completions on
2371 network drives.) Optimize by using information available from
2372 active readdir if possible. */
b19cc00c
GV
2373 len = strlen (dir_pathname);
2374 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2375 len--;
76b3903d 2376 if (dir_find_handle != INVALID_HANDLE_VALUE
b19cc00c 2377 && strnicmp (name, dir_pathname, len) == 0
76b3903d
GV
2378 && IS_DIRECTORY_SEP (name[len])
2379 && stricmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 2380 {
76b3903d
GV
2381 /* This was the last entry returned by readdir. */
2382 wfd = dir_find_data;
2383 }
2384 else
2385 {
2386 fh = FindFirstFile (name, &wfd);
2387 if (fh == INVALID_HANDLE_VALUE)
2388 {
2389 errno = ENOENT;
2390 return -1;
2391 }
2392 FindClose (fh);
480b0c5b 2393 }
480b0c5b
GV
2394 }
2395
93e0f0da
JR
2396 if (!NILP (Vw32_get_true_file_attributes)
2397 /* No access rights required to get info. */
2398 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
2399 FILE_FLAG_BACKUP_SEMANTICS, NULL))
2400 != INVALID_HANDLE_VALUE)
480b0c5b 2401 {
480b0c5b
GV
2402 /* This is more accurate in terms of gettting the correct number
2403 of links, but is quite slow (it is noticable when Emacs is
2404 making a list of file name completions). */
2405 BY_HANDLE_FILE_INFORMATION info;
2406
480b0c5b
GV
2407 if (GetFileInformationByHandle (fh, &info))
2408 {
480b0c5b 2409 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
2410 /* Might as well use file index to fake inode values, but this
2411 is not guaranteed to be unique unless we keep a handle open
2412 all the time (even then there are situations where it is
2413 not unique). Reputedly, there are at most 48 bits of info
2414 (on NTFS, presumably less on FAT). */
2415 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
480b0c5b
GV
2416 }
2417 else
2418 {
01f31dfb
AI
2419 buf->st_nlink = 1;
2420 fake_inode = 0;
2421 }
2422
93e0f0da 2423 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01f31dfb 2424 {
93e0f0da
JR
2425 buf->st_mode = _S_IFDIR;
2426 }
2427 else
2428 {
2429 switch (GetFileType (fh))
2430 {
2431 case FILE_TYPE_DISK:
2432 buf->st_mode = _S_IFREG;
2433 break;
2434 case FILE_TYPE_PIPE:
2435 buf->st_mode = _S_IFIFO;
2436 break;
2437 case FILE_TYPE_CHAR:
2438 case FILE_TYPE_UNKNOWN:
2439 default:
2440 buf->st_mode = _S_IFCHR;
2441 }
480b0c5b 2442 }
01f31dfb 2443 CloseHandle (fh);
76b3903d
GV
2444 }
2445 else
2446 {
2447 /* Don't bother to make this information more accurate. */
93e0f0da 2448 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
bc5fdfc7 2449 _S_IFDIR : _S_IFREG;
480b0c5b 2450 buf->st_nlink = 1;
76b3903d
GV
2451 fake_inode = 0;
2452 }
2453
2454#if 0
2455 /* Not sure if there is any point in this. */
2456 if (!NILP (Vw32_generate_fake_inodes))
2457 fake_inode = generate_inode_val (name);
2458 else if (fake_inode == 0)
2459 {
2460 /* For want of something better, try to make everything unique. */
2461 static DWORD gen_num = 0;
2462 fake_inode = ++gen_num;
480b0c5b 2463 }
76b3903d
GV
2464#endif
2465
2466 /* MSVC defines _ino_t to be short; other libc's might not. */
2467 if (sizeof (buf->st_ino) == 2)
2468 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2469 else
2470 buf->st_ino = fake_inode;
480b0c5b
GV
2471
2472 /* consider files to belong to current user */
2473 buf->st_uid = the_passwd.pw_uid;
2474 buf->st_gid = the_passwd.pw_gid;
2475
fbd6baed 2476 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2477 buf->st_dev = volume_info.serialnum;
2478 buf->st_rdev = volume_info.serialnum;
2479
480b0c5b
GV
2480
2481 buf->st_size = wfd.nFileSizeLow;
2482
2483 /* Convert timestamps to Unix format. */
2484 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2485 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2486 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2487 buf->st_ctime = convert_time (wfd.ftCreationTime);
2488 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2489
2490 /* determine rwx permissions */
2491 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2492 permission = _S_IREAD;
2493 else
2494 permission = _S_IREAD | _S_IWRITE;
177c0ea7 2495
480b0c5b
GV
2496 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2497 permission |= _S_IEXEC;
b3308d2e
KH
2498 else if (is_exec (name))
2499 permission |= _S_IEXEC;
480b0c5b
GV
2500
2501 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2502
2503 return 0;
2504}
2505
16bb7578
GV
2506/* Provide fstat and utime as well as stat for consistent handling of
2507 file timestamps. */
2508int
2509fstat (int desc, struct stat * buf)
2510{
2511 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2512 BY_HANDLE_FILE_INFORMATION info;
2513 DWORD fake_inode;
2514 int permission;
2515
2516 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2517 {
2518 case FILE_TYPE_DISK:
2519 buf->st_mode = _S_IFREG;
2520 if (!GetFileInformationByHandle (fh, &info))
2521 {
2522 errno = EACCES;
2523 return -1;
2524 }
2525 break;
2526 case FILE_TYPE_PIPE:
2527 buf->st_mode = _S_IFIFO;
2528 goto non_disk;
2529 case FILE_TYPE_CHAR:
2530 case FILE_TYPE_UNKNOWN:
2531 default:
2532 buf->st_mode = _S_IFCHR;
2533 non_disk:
2534 memset (&info, 0, sizeof (info));
2535 info.dwFileAttributes = 0;
2536 info.ftCreationTime = utc_base_ft;
2537 info.ftLastAccessTime = utc_base_ft;
2538 info.ftLastWriteTime = utc_base_ft;
2539 }
2540
2541 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
16bb7578 2542 buf->st_mode = _S_IFDIR;
93e0f0da
JR
2543
2544 buf->st_nlink = info.nNumberOfLinks;
2545 /* Might as well use file index to fake inode values, but this
2546 is not guaranteed to be unique unless we keep a handle open
2547 all the time (even then there are situations where it is
2548 not unique). Reputedly, there are at most 48 bits of info
2549 (on NTFS, presumably less on FAT). */
2550 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
16bb7578
GV
2551
2552 /* MSVC defines _ino_t to be short; other libc's might not. */
2553 if (sizeof (buf->st_ino) == 2)
2554 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2555 else
2556 buf->st_ino = fake_inode;
2557
2558 /* consider files to belong to current user */
2559 buf->st_uid = 0;
2560 buf->st_gid = 0;
2561
2562 buf->st_dev = info.dwVolumeSerialNumber;
2563 buf->st_rdev = info.dwVolumeSerialNumber;
2564
2565 buf->st_size = info.nFileSizeLow;
2566
2567 /* Convert timestamps to Unix format. */
2568 buf->st_mtime = convert_time (info.ftLastWriteTime);
2569 buf->st_atime = convert_time (info.ftLastAccessTime);
2570 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2571 buf->st_ctime = convert_time (info.ftCreationTime);
2572 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2573
2574 /* determine rwx permissions */
2575 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2576 permission = _S_IREAD;
2577 else
2578 permission = _S_IREAD | _S_IWRITE;
177c0ea7 2579
16bb7578
GV
2580 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2581 permission |= _S_IEXEC;
2582 else
2583 {
2584#if 0 /* no way of knowing the filename */
2585 char * p = strrchr (name, '.');
2586 if (p != NULL &&
2587 (stricmp (p, ".exe") == 0 ||
2588 stricmp (p, ".com") == 0 ||
2589 stricmp (p, ".bat") == 0 ||
2590 stricmp (p, ".cmd") == 0))
2591 permission |= _S_IEXEC;
2592#endif
2593 }
2594
2595 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2596
2597 return 0;
2598}
2599
2600int
2601utime (const char *name, struct utimbuf *times)
2602{
2603 struct utimbuf deftime;
2604 HANDLE fh;
2605 FILETIME mtime;
2606 FILETIME atime;
2607
2608 if (times == NULL)
2609 {
2610 deftime.modtime = deftime.actime = time (NULL);
2611 times = &deftime;
2612 }
2613
2614 /* Need write access to set times. */
2615 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2616 0, OPEN_EXISTING, 0, NULL);
2617 if (fh)
2618 {
2619 convert_from_time_t (times->actime, &atime);
2620 convert_from_time_t (times->modtime, &mtime);
2621 if (!SetFileTime (fh, NULL, &atime, &mtime))
2622 {
2623 CloseHandle (fh);
2624 errno = EACCES;
2625 return -1;
2626 }
2627 CloseHandle (fh);
2628 }
2629 else
2630 {
2631 errno = EINVAL;
2632 return -1;
2633 }
2634 return 0;
2635}
2636
480b0c5b
GV
2637#ifdef HAVE_SOCKETS
2638
2639/* Wrappers for winsock functions to map between our file descriptors
2640 and winsock's handles; also set h_errno for convenience.
2641
2642 To allow Emacs to run on systems which don't have winsock support
2643 installed, we dynamically link to winsock on startup if present, and
2644 otherwise provide the minimum necessary functionality
2645 (eg. gethostname). */
2646
2647/* function pointers for relevant socket functions */
2648int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2649void (PASCAL *pfn_WSASetLastError) (int iError);
2650int (PASCAL *pfn_WSAGetLastError) (void);
2651int (PASCAL *pfn_socket) (int af, int type, int protocol);
2652int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2653int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2654int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2655int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2656int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2657int (PASCAL *pfn_closesocket) (SOCKET s);
2658int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2659int (PASCAL *pfn_WSACleanup) (void);
2660
2661u_short (PASCAL *pfn_htons) (u_short hostshort);
2662u_short (PASCAL *pfn_ntohs) (u_short netshort);
2663unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2664int (PASCAL *pfn_gethostname) (char * name, int namelen);
2665struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2666struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
ecd270eb 2667int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
962955c5
JR
2668int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
2669 const char * optval, int optlen);
2670int (PASCAL *pfn_listen) (SOCKET s, int backlog);
2671int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
2672 int * namelen);
2673SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
2674int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
2675 struct sockaddr * from, int * fromlen);
2676int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
2677 const struct sockaddr * to, int tolen);
2678
f1614061
RS
2679/* SetHandleInformation is only needed to make sockets non-inheritable. */
2680BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2681#ifndef HANDLE_FLAG_INHERIT
2682#define HANDLE_FLAG_INHERIT 1
2683#endif
480b0c5b 2684
f249a012
RS
2685HANDLE winsock_lib;
2686static int winsock_inuse;
480b0c5b 2687
f249a012 2688BOOL
480b0c5b
GV
2689term_winsock (void)
2690{
f249a012 2691 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 2692 {
f249a012
RS
2693 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2694 after WSAStartup returns successfully, but it seems reasonable
2695 to allow unloading winsock anyway in that case. */
2696 if (pfn_WSACleanup () == 0 ||
2697 pfn_WSAGetLastError () == WSAENETDOWN)
2698 {
2699 if (FreeLibrary (winsock_lib))
2700 winsock_lib = NULL;
2701 return TRUE;
2702 }
480b0c5b 2703 }
f249a012 2704 return FALSE;
480b0c5b
GV
2705}
2706
f249a012
RS
2707BOOL
2708init_winsock (int load_now)
480b0c5b
GV
2709{
2710 WSADATA winsockData;
2711
f249a012
RS
2712 if (winsock_lib != NULL)
2713 return TRUE;
f1614061
RS
2714
2715 pfn_SetHandleInformation = NULL;
2716 pfn_SetHandleInformation
2717 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2718 "SetHandleInformation");
2719
480b0c5b
GV
2720 winsock_lib = LoadLibrary ("wsock32.dll");
2721
2722 if (winsock_lib != NULL)
2723 {
2724 /* dynamically link to socket functions */
2725
2726#define LOAD_PROC(fn) \
2727 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2728 goto fail;
2729
2730 LOAD_PROC( WSAStartup );
2731 LOAD_PROC( WSASetLastError );
2732 LOAD_PROC( WSAGetLastError );
2733 LOAD_PROC( socket );
2734 LOAD_PROC( bind );
2735 LOAD_PROC( connect );
2736 LOAD_PROC( ioctlsocket );
2737 LOAD_PROC( recv );
2738 LOAD_PROC( send );
2739 LOAD_PROC( closesocket );
2740 LOAD_PROC( shutdown );
2741 LOAD_PROC( htons );
2742 LOAD_PROC( ntohs );
2743 LOAD_PROC( inet_addr );
2744 LOAD_PROC( gethostname );
2745 LOAD_PROC( gethostbyname );
2746 LOAD_PROC( getservbyname );
ecd270eb 2747 LOAD_PROC( getpeername );
480b0c5b 2748 LOAD_PROC( WSACleanup );
962955c5
JR
2749 LOAD_PROC( setsockopt );
2750 LOAD_PROC( listen );
2751 LOAD_PROC( getsockname );
2752 LOAD_PROC( accept );
2753 LOAD_PROC( recvfrom );
2754 LOAD_PROC( sendto );
f249a012
RS
2755#undef LOAD_PROC
2756
480b0c5b
GV
2757 /* specify version 1.1 of winsock */
2758 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2759 {
f249a012
RS
2760 if (winsockData.wVersion != 0x101)
2761 goto fail;
2762
2763 if (!load_now)
2764 {
2765 /* Report that winsock exists and is usable, but leave
2766 socket functions disabled. I am assuming that calling
2767 WSAStartup does not require any network interaction,
2768 and in particular does not cause or require a dial-up
2769 connection to be established. */
2770
2771 pfn_WSACleanup ();
2772 FreeLibrary (winsock_lib);
2773 winsock_lib = NULL;
2774 }
2775 winsock_inuse = 0;
2776 return TRUE;
480b0c5b
GV
2777 }
2778
2779 fail:
2780 FreeLibrary (winsock_lib);
f249a012 2781 winsock_lib = NULL;
480b0c5b 2782 }
f249a012
RS
2783
2784 return FALSE;
480b0c5b
GV
2785}
2786
2787
2788int h_errno = 0;
2789
2790/* function to set h_errno for compatability; map winsock error codes to
2791 normal system codes where they overlap (non-overlapping definitions
2792 are already in <sys/socket.h> */
2793static void set_errno ()
2794{
f249a012 2795 if (winsock_lib == NULL)
480b0c5b
GV
2796 h_errno = EINVAL;
2797 else
2798 h_errno = pfn_WSAGetLastError ();
2799
2800 switch (h_errno)
2801 {
2802 case WSAEACCES: h_errno = EACCES; break;
2803 case WSAEBADF: h_errno = EBADF; break;
2804 case WSAEFAULT: h_errno = EFAULT; break;
2805 case WSAEINTR: h_errno = EINTR; break;
2806 case WSAEINVAL: h_errno = EINVAL; break;
2807 case WSAEMFILE: h_errno = EMFILE; break;
2808 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
2809 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
2810 }
2811 errno = h_errno;
2812}
2813
2814static void check_errno ()
2815{
f249a012 2816 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
2817 pfn_WSASetLastError (0);
2818}
2819
d8fcc1b9
AI
2820/* Extend strerror to handle the winsock-specific error codes. */
2821struct {
2822 int errnum;
2823 char * msg;
2824} _wsa_errlist[] = {
2825 WSAEINTR , "Interrupted function call",
2826 WSAEBADF , "Bad file descriptor",
2827 WSAEACCES , "Permission denied",
2828 WSAEFAULT , "Bad address",
2829 WSAEINVAL , "Invalid argument",
2830 WSAEMFILE , "Too many open files",
177c0ea7 2831
d8fcc1b9
AI
2832 WSAEWOULDBLOCK , "Resource temporarily unavailable",
2833 WSAEINPROGRESS , "Operation now in progress",
2834 WSAEALREADY , "Operation already in progress",
2835 WSAENOTSOCK , "Socket operation on non-socket",
2836 WSAEDESTADDRREQ , "Destination address required",
2837 WSAEMSGSIZE , "Message too long",
2838 WSAEPROTOTYPE , "Protocol wrong type for socket",
2839 WSAENOPROTOOPT , "Bad protocol option",
2840 WSAEPROTONOSUPPORT , "Protocol not supported",
2841 WSAESOCKTNOSUPPORT , "Socket type not supported",
2842 WSAEOPNOTSUPP , "Operation not supported",
2843 WSAEPFNOSUPPORT , "Protocol family not supported",
2844 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
2845 WSAEADDRINUSE , "Address already in use",
2846 WSAEADDRNOTAVAIL , "Cannot assign requested address",
2847 WSAENETDOWN , "Network is down",
2848 WSAENETUNREACH , "Network is unreachable",
2849 WSAENETRESET , "Network dropped connection on reset",
2850 WSAECONNABORTED , "Software caused connection abort",
2851 WSAECONNRESET , "Connection reset by peer",
2852 WSAENOBUFS , "No buffer space available",
2853 WSAEISCONN , "Socket is already connected",
2854 WSAENOTCONN , "Socket is not connected",
2855 WSAESHUTDOWN , "Cannot send after socket shutdown",
2856 WSAETOOMANYREFS , "Too many references", /* not sure */
2857 WSAETIMEDOUT , "Connection timed out",
2858 WSAECONNREFUSED , "Connection refused",
2859 WSAELOOP , "Network loop", /* not sure */
2860 WSAENAMETOOLONG , "Name is too long",
2861 WSAEHOSTDOWN , "Host is down",
2862 WSAEHOSTUNREACH , "No route to host",
2863 WSAENOTEMPTY , "Buffer not empty", /* not sure */
2864 WSAEPROCLIM , "Too many processes",
2865 WSAEUSERS , "Too many users", /* not sure */
2866 WSAEDQUOT , "Double quote in host name", /* really not sure */
2867 WSAESTALE , "Data is stale", /* not sure */
2868 WSAEREMOTE , "Remote error", /* not sure */
177c0ea7 2869
d8fcc1b9
AI
2870 WSASYSNOTREADY , "Network subsystem is unavailable",
2871 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
2872 WSANOTINITIALISED , "Winsock not initialized successfully",
2873 WSAEDISCON , "Graceful shutdown in progress",
2874#ifdef WSAENOMORE
2875 WSAENOMORE , "No more operations allowed", /* not sure */
2876 WSAECANCELLED , "Operation cancelled", /* not sure */
2877 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
2878 WSAEINVALIDPROVIDER , "Invalid service provider version number",
2879 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
2880 WSASYSCALLFAILURE , "System call failured",
2881 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
2882 WSATYPE_NOT_FOUND , "Class type not found",
2883 WSA_E_NO_MORE , "No more resources available", /* really not sure */
2884 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
2885 WSAEREFUSED , "Operation refused", /* not sure */
2886#endif
177c0ea7 2887
d8fcc1b9
AI
2888 WSAHOST_NOT_FOUND , "Host not found",
2889 WSATRY_AGAIN , "Authoritative host not found during name lookup",
2890 WSANO_RECOVERY , "Non-recoverable error during name lookup",
2891 WSANO_DATA , "Valid name, no data record of requested type",
2892
2893 -1, NULL
2894};
2895
2896char *
2897sys_strerror(int error_no)
2898{
2899 int i;
2900 static char unknown_msg[40];
2901
a302c7ae
AI
2902 if (error_no >= 0 && error_no < sys_nerr)
2903 return sys_errlist[error_no];
d8fcc1b9
AI
2904
2905 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
2906 if (_wsa_errlist[i].errnum == error_no)
2907 return _wsa_errlist[i].msg;
2908
2909 sprintf(unknown_msg, "Unidentified error: %d", error_no);
2910 return unknown_msg;
2911}
2912
480b0c5b
GV
2913/* [andrewi 3-May-96] I've had conflicting results using both methods,
2914 but I believe the method of keeping the socket handle separate (and
2915 insuring it is not inheritable) is the correct one. */
2916
2917//#define SOCK_REPLACE_HANDLE
2918
2919#ifdef SOCK_REPLACE_HANDLE
2920#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2921#else
2922#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2923#endif
2924
962955c5
JR
2925int socket_to_fd (SOCKET s);
2926
480b0c5b
GV
2927int
2928sys_socket(int af, int type, int protocol)
2929{
962955c5 2930 SOCKET s;
480b0c5b 2931
f249a012 2932 if (winsock_lib == NULL)
480b0c5b
GV
2933 {
2934 h_errno = ENETDOWN;
2935 return INVALID_SOCKET;
2936 }
2937
2938 check_errno ();
2939
2940 /* call the real socket function */
962955c5 2941 s = pfn_socket (af, type, protocol);
177c0ea7 2942
480b0c5b 2943 if (s != INVALID_SOCKET)
962955c5 2944 return socket_to_fd (s);
480b0c5b 2945
962955c5
JR
2946 set_errno ();
2947 return -1;
2948}
2949
2950/* Convert a SOCKET to a file descriptor. */
2951int
2952socket_to_fd (SOCKET s)
2953{
2954 int fd;
2955 child_process * cp;
2956
2957 /* Although under NT 3.5 _open_osfhandle will accept a socket
2958 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2959 that does not work under NT 3.1. However, we can get the same
2960 effect by using a backdoor function to replace an existing
2961 descriptor handle with the one we want. */
2962
2963 /* allocate a file descriptor (with appropriate flags) */
2964 fd = _open ("NUL:", _O_RDWR);
2965 if (fd >= 0)
2966 {
480b0c5b 2967#ifdef SOCK_REPLACE_HANDLE
962955c5
JR
2968 /* now replace handle to NUL with our socket handle */
2969 CloseHandle ((HANDLE) _get_osfhandle (fd));
2970 _free_osfhnd (fd);
2971 _set_osfhnd (fd, s);
2972 /* setmode (fd, _O_BINARY); */
480b0c5b 2973#else
962955c5
JR
2974 /* Make a non-inheritable copy of the socket handle. Note
2975 that it is possible that sockets aren't actually kernel
2976 handles, which appears to be the case on Windows 9x when
2977 the MS Proxy winsock client is installed. */
2978 {
2979 /* Apparently there is a bug in NT 3.51 with some service
2980 packs, which prevents using DuplicateHandle to make a
2981 socket handle non-inheritable (causes WSACleanup to
2982 hang). The work-around is to use SetHandleInformation
2983 instead if it is available and implemented. */
2984 if (pfn_SetHandleInformation)
480b0c5b 2985 {
962955c5
JR
2986 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
2987 }
2988 else
2989 {
2990 HANDLE parent = GetCurrentProcess ();
2991 HANDLE new_s = INVALID_HANDLE_VALUE;
2992
2993 if (DuplicateHandle (parent,
2994 (HANDLE) s,
2995 parent,
2996 &new_s,
2997 0,
2998 FALSE,
2999 DUPLICATE_SAME_ACCESS))
f1614061 3000 {
962955c5
JR
3001 /* It is possible that DuplicateHandle succeeds even
3002 though the socket wasn't really a kernel handle,
3003 because a real handle has the same value. So
3004 test whether the new handle really is a socket. */
3005 long nonblocking = 0;
3006 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
ca149beb 3007 {
962955c5
JR
3008 pfn_closesocket (s);
3009 s = (SOCKET) new_s;
3010 }
3011 else
3012 {
3013 CloseHandle (new_s);
3014 }
177c0ea7 3015 }
480b0c5b 3016 }
962955c5
JR
3017 }
3018 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
3019#endif
3020
962955c5
JR
3021 /* set our own internal flags */
3022 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
480b0c5b 3023
962955c5
JR
3024 cp = new_child ();
3025 if (cp)
3026 {
3027 cp->fd = fd;
3028 cp->status = STATUS_READ_ACKNOWLEDGED;
480b0c5b 3029
962955c5
JR
3030 /* attach child_process to fd_info */
3031 if (fd_info[ fd ].cp != NULL)
3032 {
3033 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3034 abort ();
480b0c5b
GV
3035 }
3036
962955c5
JR
3037 fd_info[ fd ].cp = cp;
3038
3039 /* success! */
3040 winsock_inuse++; /* count open sockets */
3041 return fd;
480b0c5b 3042 }
480b0c5b 3043
962955c5
JR
3044 /* clean up */
3045 _close (fd);
3046 }
3047 pfn_closesocket (s);
3048 h_errno = EMFILE;
480b0c5b
GV
3049 return -1;
3050}
3051
3052
3053int
3054sys_bind (int s, const struct sockaddr * addr, int namelen)
3055{
f249a012 3056 if (winsock_lib == NULL)
480b0c5b
GV
3057 {
3058 h_errno = ENOTSOCK;
3059 return SOCKET_ERROR;
3060 }
3061
3062 check_errno ();
3063 if (fd_info[s].flags & FILE_SOCKET)
3064 {
3065 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3066 if (rc == SOCKET_ERROR)
3067 set_errno ();
3068 return rc;
3069 }
3070 h_errno = ENOTSOCK;
3071 return SOCKET_ERROR;
3072}
3073
3074
3075int
3076sys_connect (int s, const struct sockaddr * name, int namelen)
3077{
f249a012 3078 if (winsock_lib == NULL)
480b0c5b
GV
3079 {
3080 h_errno = ENOTSOCK;
3081 return SOCKET_ERROR;
3082 }
3083
3084 check_errno ();
3085 if (fd_info[s].flags & FILE_SOCKET)
3086 {
3087 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3088 if (rc == SOCKET_ERROR)
3089 set_errno ();
3090 return rc;
3091 }
3092 h_errno = ENOTSOCK;
3093 return SOCKET_ERROR;
3094}
3095
3096u_short
3097sys_htons (u_short hostshort)
3098{
f249a012 3099 return (winsock_lib != NULL) ?
480b0c5b
GV
3100 pfn_htons (hostshort) : hostshort;
3101}
3102
3103u_short
3104sys_ntohs (u_short netshort)
3105{
f249a012 3106 return (winsock_lib != NULL) ?
480b0c5b
GV
3107 pfn_ntohs (netshort) : netshort;
3108}
3109
3110unsigned long
3111sys_inet_addr (const char * cp)
3112{
f249a012 3113 return (winsock_lib != NULL) ?
480b0c5b
GV
3114 pfn_inet_addr (cp) : INADDR_NONE;
3115}
3116
3117int
3118sys_gethostname (char * name, int namelen)
3119{
f249a012 3120 if (winsock_lib != NULL)
480b0c5b
GV
3121 return pfn_gethostname (name, namelen);
3122
3123 if (namelen > MAX_COMPUTERNAME_LENGTH)
a302c7ae 3124 return !GetComputerName (name, (DWORD *)&namelen);
480b0c5b
GV
3125
3126 h_errno = EFAULT;
3127 return SOCKET_ERROR;
3128}
3129
3130struct hostent *
3131sys_gethostbyname(const char * name)
3132{
3133 struct hostent * host;
3134
f249a012 3135 if (winsock_lib == NULL)
480b0c5b
GV
3136 {
3137 h_errno = ENETDOWN;
3138 return NULL;
3139 }
3140
3141 check_errno ();
3142 host = pfn_gethostbyname (name);
3143 if (!host)
3144 set_errno ();
3145 return host;
3146}
3147
3148struct servent *
3149sys_getservbyname(const char * name, const char * proto)
3150{
3151 struct servent * serv;
3152
f249a012 3153 if (winsock_lib == NULL)
480b0c5b
GV
3154 {
3155 h_errno = ENETDOWN;
3156 return NULL;
3157 }
3158
3159 check_errno ();
3160 serv = pfn_getservbyname (name, proto);
3161 if (!serv)
3162 set_errno ();
3163 return serv;
3164}
3165
ecd270eb
JR
3166int
3167sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3168{
3169 if (winsock_lib == NULL)
3170 {
3171 h_errno = ENETDOWN;
3172 return SOCKET_ERROR;
3173 }
3174
3175 check_errno ();
3176 if (fd_info[s].flags & FILE_SOCKET)
3177 {
3178 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3179 if (rc == SOCKET_ERROR)
3180 set_errno ();
3181 return rc;
3182 }
3183 h_errno = ENOTSOCK;
3184 return SOCKET_ERROR;
3185}
3186
3187
380961a6
GV
3188int
3189sys_shutdown (int s, int how)
3190{
380961a6
GV
3191 if (winsock_lib == NULL)
3192 {
3193 h_errno = ENETDOWN;
3194 return SOCKET_ERROR;
3195 }
3196
3197 check_errno ();
3198 if (fd_info[s].flags & FILE_SOCKET)
3199 {
3200 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
962955c5
JR
3201 if (rc == SOCKET_ERROR)
3202 set_errno ();
3203 return rc;
3204 }
3205 h_errno = ENOTSOCK;
3206 return SOCKET_ERROR;
3207}
3208
3209int
3210sys_setsockopt (int s, int level, int optname, const char * optval, int optlen)
3211{
3212 if (winsock_lib == NULL)
3213 {
3214 h_errno = ENETDOWN;
3215 return SOCKET_ERROR;
3216 }
3217
3218 check_errno ();
3219 if (fd_info[s].flags & FILE_SOCKET)
3220 {
3221 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
3222 optval, optlen);
3223 if (rc == SOCKET_ERROR)
3224 set_errno ();
3225 return rc;
3226 }
3227 h_errno = ENOTSOCK;
177c0ea7 3228 return SOCKET_ERROR;
962955c5
JR
3229}
3230
3231int
3232sys_listen (int s, int backlog)
3233{
3234 if (winsock_lib == NULL)
3235 {
3236 h_errno = ENETDOWN;
3237 return SOCKET_ERROR;
3238 }
3239
3240 check_errno ();
3241 if (fd_info[s].flags & FILE_SOCKET)
3242 {
3243 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3244 if (rc == SOCKET_ERROR)
3245 set_errno ();
3246 return rc;
3247 }
3248 h_errno = ENOTSOCK;
177c0ea7 3249 return SOCKET_ERROR;
962955c5
JR
3250}
3251
3252int
3253sys_getsockname (int s, struct sockaddr * name, int * namelen)
3254{
3255 if (winsock_lib == NULL)
3256 {
3257 h_errno = ENETDOWN;
3258 return SOCKET_ERROR;
3259 }
3260
3261 check_errno ();
3262 if (fd_info[s].flags & FILE_SOCKET)
3263 {
3264 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3265 if (rc == SOCKET_ERROR)
3266 set_errno ();
3267 return rc;
3268 }
3269 h_errno = ENOTSOCK;
177c0ea7 3270 return SOCKET_ERROR;
962955c5
JR
3271}
3272
3273int
3274sys_accept (int s, struct sockaddr * addr, int * addrlen)
3275{
3276 if (winsock_lib == NULL)
3277 {
3278 h_errno = ENETDOWN;
3279 return -1;
3280 }
3281
3282 check_errno ();
3283 if (fd_info[s].flags & FILE_SOCKET)
3284 {
a0ad1860
JB
3285 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
3286 if (t != INVALID_SOCKET)
3287 return socket_to_fd (t);
962955c5
JR
3288
3289 set_errno ();
3290 return -1;
3291 }
3292 h_errno = ENOTSOCK;
3293 return -1;
3294}
3295
3296int
3297sys_recvfrom (int s, char * buf, int len, int flags,
3298 struct sockaddr * from, int * fromlen)
3299{
3300 if (winsock_lib == NULL)
3301 {
3302 h_errno = ENETDOWN;
3303 return SOCKET_ERROR;
3304 }
3305
3306 check_errno ();
3307 if (fd_info[s].flags & FILE_SOCKET)
3308 {
3309 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3310 if (rc == SOCKET_ERROR)
3311 set_errno ();
3312 return rc;
3313 }
3314 h_errno = ENOTSOCK;
3315 return SOCKET_ERROR;
3316}
3317
3318int
3319sys_sendto (int s, const char * buf, int len, int flags,
3320 const struct sockaddr * to, int tolen)
3321{
3322 if (winsock_lib == NULL)
3323 {
3324 h_errno = ENETDOWN;
3325 return SOCKET_ERROR;
3326 }
3327
3328 check_errno ();
3329 if (fd_info[s].flags & FILE_SOCKET)
3330 {
3331 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
380961a6
GV
3332 if (rc == SOCKET_ERROR)
3333 set_errno ();
3334 return rc;
3335 }
3336 h_errno = ENOTSOCK;
3337 return SOCKET_ERROR;
3338}
3339
ecd270eb
JR
3340/* Windows does not have an fcntl function. Provide an implementation
3341 solely for making sockets non-blocking. */
3342int
3343fcntl (int s, int cmd, int options)
3344{
3345 if (winsock_lib == NULL)
3346 {
3347 h_errno = ENETDOWN;
3348 return -1;
3349 }
3350
3351 check_errno ();
3352 if (fd_info[s].flags & FILE_SOCKET)
3353 {
3354 if (cmd == F_SETFL && options == O_NDELAY)
3355 {
3356 unsigned long nblock = 1;
3357 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3358 if (rc == SOCKET_ERROR)
3359 set_errno();
3360 /* Keep track of the fact that we set this to non-blocking. */
3361 fd_info[s].flags |= FILE_NDELAY;
3362 return rc;
3363 }
3364 else
3365 {
3366 h_errno = EINVAL;
3367 return SOCKET_ERROR;
3368 }
3369 }
3370 h_errno = ENOTSOCK;
3371 return SOCKET_ERROR;
3372}
3373
480b0c5b
GV
3374#endif /* HAVE_SOCKETS */
3375
3376
3377/* Shadow main io functions: we need to handle pipes and sockets more
3378 intelligently, and implement non-blocking mode as well. */
3379
3380int
3381sys_close (int fd)
3382{
3383 int rc;
3384
3385 if (fd < 0 || fd >= MAXDESC)
3386 {
3387 errno = EBADF;
3388 return -1;
3389 }
3390
3391 if (fd_info[fd].cp)
3392 {
3393 child_process * cp = fd_info[fd].cp;
3394
3395 fd_info[fd].cp = NULL;
3396
3397 if (CHILD_ACTIVE (cp))
3398 {
3399 /* if last descriptor to active child_process then cleanup */
3400 int i;
3401 for (i = 0; i < MAXDESC; i++)
3402 {
3403 if (i == fd)
3404 continue;
3405 if (fd_info[i].cp == cp)
3406 break;
3407 }
3408 if (i == MAXDESC)
3409 {
f249a012 3410#ifdef HAVE_SOCKETS
480b0c5b
GV
3411 if (fd_info[fd].flags & FILE_SOCKET)
3412 {
f249a012
RS
3413#ifndef SOCK_REPLACE_HANDLE
3414 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3415
3416 pfn_shutdown (SOCK_HANDLE (fd), 2);
3417 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
3418#endif
3419 winsock_inuse--; /* count open sockets */
480b0c5b
GV
3420 }
3421#endif
3422 delete_child (cp);
3423 }
3424 }
3425 }
3426
3427 /* Note that sockets do not need special treatment here (at least on
e9e23e23 3428 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
3429 closesocket is equivalent to CloseHandle, which is to be expected
3430 because socket handles are fully fledged kernel handles. */
3431 rc = _close (fd);
3432
3433 if (rc == 0)
3434 fd_info[fd].flags = 0;
3435
3436 return rc;
3437}
3438
3439int
3440sys_dup (int fd)
3441{
3442 int new_fd;
3443
3444 new_fd = _dup (fd);
3445 if (new_fd >= 0)
3446 {
3447 /* duplicate our internal info as well */
3448 fd_info[new_fd] = fd_info[fd];
3449 }
3450 return new_fd;
3451}
3452
3453
3454int
3455sys_dup2 (int src, int dst)
3456{
3457 int rc;
3458
3459 if (dst < 0 || dst >= MAXDESC)
3460 {
3461 errno = EBADF;
3462 return -1;
3463 }
3464
3465 /* make sure we close the destination first if it's a pipe or socket */
3466 if (src != dst && fd_info[dst].flags != 0)
3467 sys_close (dst);
177c0ea7 3468
480b0c5b
GV
3469 rc = _dup2 (src, dst);
3470 if (rc == 0)
3471 {
3472 /* duplicate our internal info as well */
3473 fd_info[dst] = fd_info[src];
3474 }
3475 return rc;
3476}
3477
480b0c5b
GV
3478/* Unix pipe() has only one arg */
3479int
3480sys_pipe (int * phandles)
3481{
3482 int rc;
3483 unsigned flags;
480b0c5b 3484
76b3903d
GV
3485 /* make pipe handles non-inheritable; when we spawn a child, we
3486 replace the relevant handle with an inheritable one. Also put
3487 pipes into binary mode; we will do text mode translation ourselves
3488 if required. */
3489 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
3490
3491 if (rc == 0)
3492 {
cb72110d
JR
3493 /* Protect against overflow, since Windows can open more handles than
3494 our fd_info array has room for. */
3495 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
3496 {
3497 _close (phandles[0]);
3498 _close (phandles[1]);
3499 rc = -1;
3500 }
3501 else
3502 {
3503 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
3504 fd_info[phandles[0]].flags = flags;
480b0c5b 3505
cb72110d
JR
3506 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
3507 fd_info[phandles[1]].flags = flags;
3508 }
480b0c5b
GV
3509 }
3510
3511 return rc;
3512}
3513
f7554349 3514/* From ntproc.c */
78806724 3515extern int w32_pipe_read_delay;
f7554349 3516
480b0c5b
GV
3517/* Function to do blocking read of one byte, needed to implement
3518 select. It is only allowed on sockets and pipes. */
3519int
3520_sys_read_ahead (int fd)
3521{
3522 child_process * cp;
3523 int rc;
3524
3525 if (fd < 0 || fd >= MAXDESC)
3526 return STATUS_READ_ERROR;
3527
3528 cp = fd_info[fd].cp;
3529
3530 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
3531 return STATUS_READ_ERROR;
3532
3533 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
3534 || (fd_info[fd].flags & FILE_READ) == 0)
3535 {
3536 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
3537 abort ();
3538 }
177c0ea7 3539
480b0c5b 3540 cp->status = STATUS_READ_IN_PROGRESS;
177c0ea7 3541
480b0c5b 3542 if (fd_info[fd].flags & FILE_PIPE)
f7554349 3543 {
f7554349
KH
3544 rc = _read (fd, &cp->chr, sizeof (char));
3545
3546 /* Give subprocess time to buffer some more output for us before
e9e23e23 3547 reporting that input is available; we need this because Windows 95
f7554349
KH
3548 connects DOS programs to pipes by making the pipe appear to be
3549 the normal console stdout - as a result most DOS programs will
3550 write to stdout without buffering, ie. one character at a
fbd6baed 3551 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
3552 shell on NT is very slow if we don't do this. */
3553 if (rc > 0)
3554 {
78806724 3555 int wait = w32_pipe_read_delay;
f7554349
KH
3556
3557 if (wait > 0)
3558 Sleep (wait);
3559 else if (wait < 0)
3560 while (++wait <= 0)
3561 /* Yield remainder of our time slice, effectively giving a
3562 temporary priority boost to the child process. */
3563 Sleep (0);
3564 }
3565 }
480b0c5b
GV
3566#ifdef HAVE_SOCKETS
3567 else if (fd_info[fd].flags & FILE_SOCKET)
ecd270eb
JR
3568 {
3569 unsigned long nblock = 0;
3570 /* We always want this to block, so temporarily disable NDELAY. */
3571 if (fd_info[fd].flags & FILE_NDELAY)
3572 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3573
3574 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
3575
3576 if (fd_info[fd].flags & FILE_NDELAY)
3577 {
3578 nblock = 1;
3579 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3580 }
3581 }
480b0c5b 3582#endif
177c0ea7 3583
480b0c5b
GV
3584 if (rc == sizeof (char))
3585 cp->status = STATUS_READ_SUCCEEDED;
3586 else
3587 cp->status = STATUS_READ_FAILED;
3588
3589 return cp->status;
3590}
3591
3592int
3593sys_read (int fd, char * buffer, unsigned int count)
3594{
3595 int nchars;
480b0c5b
GV
3596 int to_read;
3597 DWORD waiting;
76b3903d 3598 char * orig_buffer = buffer;
480b0c5b
GV
3599
3600 if (fd < 0 || fd >= MAXDESC)
3601 {
3602 errno = EBADF;
3603 return -1;
3604 }
3605
3606 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
3607 {
3608 child_process *cp = fd_info[fd].cp;
3609
3610 if ((fd_info[fd].flags & FILE_READ) == 0)
3611 {
3612 errno = EBADF;
3613 return -1;
3614 }
3615
76b3903d
GV
3616 nchars = 0;
3617
3618 /* re-read CR carried over from last read */
3619 if (fd_info[fd].flags & FILE_LAST_CR)
3620 {
3621 if (fd_info[fd].flags & FILE_BINARY) abort ();
3622 *buffer++ = 0x0d;
3623 count--;
3624 nchars++;
f52eb3ef 3625 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
3626 }
3627
480b0c5b
GV
3628 /* presence of a child_process structure means we are operating in
3629 non-blocking mode - otherwise we just call _read directly.
3630 Note that the child_process structure might be missing because
3631 reap_subprocess has been called; in this case the pipe is
3632 already broken, so calling _read on it is okay. */
3633 if (cp)
3634 {
3635 int current_status = cp->status;
3636
3637 switch (current_status)
3638 {
3639 case STATUS_READ_FAILED:
3640 case STATUS_READ_ERROR:
f52eb3ef
GV
3641 /* report normal EOF if nothing in buffer */
3642 if (nchars <= 0)
3643 fd_info[fd].flags |= FILE_AT_EOF;
3644 return nchars;
480b0c5b
GV
3645
3646 case STATUS_READ_READY:
3647 case STATUS_READ_IN_PROGRESS:
3648 DebPrint (("sys_read called when read is in progress\n"));
3649 errno = EWOULDBLOCK;
3650 return -1;
3651
3652 case STATUS_READ_SUCCEEDED:
3653 /* consume read-ahead char */
3654 *buffer++ = cp->chr;
3655 count--;
76b3903d 3656 nchars++;
480b0c5b
GV
3657 cp->status = STATUS_READ_ACKNOWLEDGED;
3658 ResetEvent (cp->char_avail);
3659
3660 case STATUS_READ_ACKNOWLEDGED:
3661 break;
3662
3663 default:
3664 DebPrint (("sys_read: bad status %d\n", current_status));
3665 errno = EBADF;
3666 return -1;
3667 }
3668
3669 if (fd_info[fd].flags & FILE_PIPE)
3670 {
3671 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
3672 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
3673
3674 if (to_read > 0)
3675 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
3676 }
3677#ifdef HAVE_SOCKETS
3678 else /* FILE_SOCKET */
3679 {
f249a012 3680 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3681
3682 /* do the equivalent of a non-blocking read */
3683 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 3684 if (waiting == 0 && nchars == 0)
480b0c5b
GV
3685 {
3686 h_errno = errno = EWOULDBLOCK;
3687 return -1;
3688 }
3689
480b0c5b
GV
3690 if (waiting)
3691 {
3692 /* always use binary mode for sockets */
76b3903d
GV
3693 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
3694 if (res == SOCKET_ERROR)
480b0c5b
GV
3695 {
3696 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
3697 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
3698 set_errno ();
3699 return -1;
480b0c5b 3700 }
76b3903d 3701 nchars += res;
480b0c5b
GV
3702 }
3703 }
3704#endif
3705 }
3706 else
f52eb3ef
GV
3707 {
3708 int nread = _read (fd, buffer, count);
3709 if (nread >= 0)
3710 nchars += nread;
3711 else if (nchars == 0)
3712 nchars = nread;
3713 }
76b3903d 3714
f52eb3ef
GV
3715 if (nchars <= 0)
3716 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 3717 /* Perform text mode translation if required. */
f52eb3ef 3718 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
3719 {
3720 nchars = crlf_to_lf (nchars, orig_buffer);
3721 /* If buffer contains only CR, return that. To be absolutely
3722 sure we should attempt to read the next char, but in
3723 practice a CR to be followed by LF would not appear by
3724 itself in the buffer. */
3725 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
3726 {
3727 fd_info[fd].flags |= FILE_LAST_CR;
3728 nchars--;
3729 }
76b3903d 3730 }
480b0c5b
GV
3731 }
3732 else
3733 nchars = _read (fd, buffer, count);
3734
76b3903d 3735 return nchars;
480b0c5b
GV
3736}
3737
3738/* For now, don't bother with a non-blocking mode */
3739int
3740sys_write (int fd, const void * buffer, unsigned int count)
3741{
3742 int nchars;
3743
3744 if (fd < 0 || fd >= MAXDESC)
3745 {
3746 errno = EBADF;
3747 return -1;
3748 }
3749
3750 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
3751 {
3752 if ((fd_info[fd].flags & FILE_WRITE) == 0)
3753 {
3754 errno = EBADF;
3755 return -1;
3756 }
3757
3758 /* Perform text mode translation if required. */
3759 if ((fd_info[fd].flags & FILE_BINARY) == 0)
3760 {
3761 char * tmpbuf = alloca (count * 2);
3762 unsigned char * src = (void *)buffer;
3763 unsigned char * dst = tmpbuf;
3764 int nbytes = count;
3765
3766 while (1)
3767 {
3768 unsigned char *next;
3769 /* copy next line or remaining bytes */
3770 next = _memccpy (dst, src, '\n', nbytes);
3771 if (next)
3772 {
3773 /* copied one line ending with '\n' */
3774 int copied = next - dst;
3775 nbytes -= copied;
3776 src += copied;
3777 /* insert '\r' before '\n' */
3778 next[-1] = '\r';
3779 next[0] = '\n';
3780 dst = next + 1;
3781 count++;
177c0ea7 3782 }
76b3903d
GV
3783 else
3784 /* copied remaining partial line -> now finished */
3785 break;
3786 }
3787 buffer = tmpbuf;
3788 }
3789 }
3790
480b0c5b
GV
3791#ifdef HAVE_SOCKETS
3792 if (fd_info[fd].flags & FILE_SOCKET)
3793 {
30a32e0e 3794 unsigned long nblock = 0;
f249a012 3795 if (winsock_lib == NULL) abort ();
30a32e0e
JR
3796
3797 /* TODO: implement select() properly so non-blocking I/O works. */
3798 /* For now, make sure the write blocks. */
3799 if (fd_info[fd].flags & FILE_NDELAY)
3800 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3801
480b0c5b 3802 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
30a32e0e
JR
3803
3804 /* Set the socket back to non-blocking if it was before,
3805 for other operations that support it. */
3806 if (fd_info[fd].flags & FILE_NDELAY)
3807 {
3808 nblock = 1;
3809 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3810 }
3811
480b0c5b
GV
3812 if (nchars == SOCKET_ERROR)
3813 {
670773af 3814 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
480b0c5b
GV
3815 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3816 set_errno ();
3817 }
3818 }
3819 else
3820#endif
3821 nchars = _write (fd, buffer, count);
3822
3823 return nchars;
3824}
3825
f52eb3ef
GV
3826static void
3827check_windows_init_file ()
3828{
3829 extern int noninteractive, inhibit_window_system;
3830
3831 /* A common indication that Emacs is not installed properly is when
3832 it cannot find the Windows installation file. If this file does
3833 not exist in the expected place, tell the user. */
3834
177c0ea7 3835 if (!noninteractive && !inhibit_window_system)
d54abccd
GV
3836 {
3837 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 3838 Lisp_Object objs[2];
96ef7d42 3839 Lisp_Object full_load_path;
d54abccd
GV
3840 Lisp_Object init_file;
3841 int fd;
f52eb3ef 3842
a0b9c838
GV
3843 objs[0] = Vload_path;
3844 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
3845 full_load_path = Fappend (2, objs);
d54abccd 3846 init_file = build_string ("term/w32-win");
7d032932 3847 fd = openp (full_load_path, init_file, Vload_suffixes, NULL, Qnil);
177c0ea7 3848 if (fd < 0)
d54abccd 3849 {
96ef7d42 3850 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d5db4077
KR
3851 char *init_file_name = SDATA (init_file);
3852 char *load_path = SDATA (load_path_print);
d54abccd
GV
3853 char *buffer = alloca (1024);
3854
177c0ea7 3855 sprintf (buffer,
d54abccd
GV
3856 "The Emacs Windows initialization file \"%s.el\" "
3857 "could not be found in your Emacs installation. "
3858 "Emacs checked the following directories for this file:\n"
3859 "\n%s\n\n"
3860 "When Emacs cannot find this file, it usually means that it "
3861 "was not installed properly, or its distribution file was "
3862 "not unpacked properly.\nSee the README.W32 file in the "
3863 "top-level Emacs directory for more information.",
3864 init_file_name, load_path);
3865 MessageBox (NULL,
3866 buffer,
3867 "Emacs Abort Dialog",
3868 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
3869 /* Use the low-level Emacs abort. */
3870#undef abort
d54abccd
GV
3871 abort ();
3872 }
3873 else
3874 {
a302c7ae 3875 _close (fd);
d54abccd 3876 }
f52eb3ef 3877 }
f52eb3ef 3878}
480b0c5b
GV
3879
3880void
3881term_ntproc ()
3882{
3883#ifdef HAVE_SOCKETS
3884 /* shutdown the socket interface if necessary */
3885 term_winsock ();
3886#endif
52c7f9ee
JR
3887
3888 term_w32select ();
480b0c5b
GV
3889}
3890
3891void
3892init_ntproc ()
3893{
3894#ifdef HAVE_SOCKETS
f249a012
RS
3895 /* Initialise the socket interface now if available and requested by
3896 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 3897 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
3898 also be used to dynamically load or reload winsock).
3899
3900 Conveniently, init_environment is called before us, so
3901 PRELOAD_WINSOCK can be set in the registry. */
3902
3903 /* Always initialize this correctly. */
3904 winsock_lib = NULL;
3905
3906 if (getenv ("PRELOAD_WINSOCK") != NULL)
3907 init_winsock (TRUE);
480b0c5b
GV
3908#endif
3909
3910 /* Initial preparation for subprocess support: replace our standard
3911 handles with non-inheritable versions. */
3912 {
3913 HANDLE parent;
3914 HANDLE stdin_save = INVALID_HANDLE_VALUE;
3915 HANDLE stdout_save = INVALID_HANDLE_VALUE;
3916 HANDLE stderr_save = INVALID_HANDLE_VALUE;
3917
3918 parent = GetCurrentProcess ();
3919
3920 /* ignore errors when duplicating and closing; typically the
3921 handles will be invalid when running as a gui program. */
177c0ea7
JB
3922 DuplicateHandle (parent,
3923 GetStdHandle (STD_INPUT_HANDLE),
480b0c5b 3924 parent,
177c0ea7
JB
3925 &stdin_save,
3926 0,
3927 FALSE,
480b0c5b 3928 DUPLICATE_SAME_ACCESS);
177c0ea7 3929
480b0c5b
GV
3930 DuplicateHandle (parent,
3931 GetStdHandle (STD_OUTPUT_HANDLE),
3932 parent,
3933 &stdout_save,
3934 0,
3935 FALSE,
3936 DUPLICATE_SAME_ACCESS);
177c0ea7 3937
480b0c5b
GV
3938 DuplicateHandle (parent,
3939 GetStdHandle (STD_ERROR_HANDLE),
3940 parent,
3941 &stderr_save,
3942 0,
3943 FALSE,
3944 DUPLICATE_SAME_ACCESS);
177c0ea7 3945
480b0c5b
GV
3946 fclose (stdin);
3947 fclose (stdout);
3948 fclose (stderr);
3949
3950 if (stdin_save != INVALID_HANDLE_VALUE)
3951 _open_osfhandle ((long) stdin_save, O_TEXT);
3952 else
76b3903d
GV
3953 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
3954 _fdopen (0, "r");
480b0c5b
GV
3955
3956 if (stdout_save != INVALID_HANDLE_VALUE)
3957 _open_osfhandle ((long) stdout_save, O_TEXT);
3958 else
76b3903d
GV
3959 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3960 _fdopen (1, "w");
480b0c5b
GV
3961
3962 if (stderr_save != INVALID_HANDLE_VALUE)
3963 _open_osfhandle ((long) stderr_save, O_TEXT);
3964 else
76b3903d
GV
3965 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3966 _fdopen (2, "w");
480b0c5b
GV
3967 }
3968
3969 /* unfortunately, atexit depends on implementation of malloc */
3970 /* atexit (term_ntproc); */
3971 signal (SIGABRT, term_ntproc);
76b3903d
GV
3972
3973 /* determine which drives are fixed, for GetCachedVolumeInformation */
3974 {
3975 /* GetDriveType must have trailing backslash. */
3976 char drive[] = "A:\\";
3977
3978 /* Loop over all possible drive letters */
3979 while (*drive <= 'Z')
3980 {
3981 /* Record if this drive letter refers to a fixed drive. */
177c0ea7 3982 fixed_drives[DRIVE_INDEX (*drive)] =
76b3903d
GV
3983 (GetDriveType (drive) == DRIVE_FIXED);
3984
3985 (*drive)++;
3986 }
a302c7ae
AI
3987
3988 /* Reset the volume info cache. */
3989 volume_cache = NULL;
76b3903d 3990 }
177c0ea7 3991
d54abccd
GV
3992 /* Check to see if Emacs has been installed correctly. */
3993 check_windows_init_file ();
480b0c5b
GV
3994}
3995
9785d95b
BK
3996/*
3997 globals_of_w32 is used to initialize those global variables that
3998 must always be initialized on startup even when the global variable
3999 initialized is non zero (see the function main in emacs.c).
4000*/
4001void globals_of_w32 ()
4002{
4003 g_b_init_is_windows_9x = 0;
4004 g_b_init_open_process_token = 0;
4005 g_b_init_get_token_information = 0;
4006 g_b_init_lookup_account_sid = 0;
4007 g_b_init_get_sid_identifier_authority = 0;
4008}
4009
480b0c5b 4010/* end of nt.c */
ab5796a9
MB
4011
4012/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4013 (do not change this comment) */