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