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