XEmacs 21.2-b1
[chise/xemacs-chise.git.1] / src / nt.c
1 /* Utility and Unix shadow routines for XEmacs on Windows NT.
2    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20
21
22    Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */
23
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
26
27 #include <config.h>
28
29 #undef signal
30 #define getwd _getwd
31 #include "lisp.h"
32 #undef getwd
33
34 #include "systime.h"
35 #include "syssignal.h"
36 #include "sysproc.h"
37
38 #include <ctype.h>
39 #include <direct.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <io.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <stddef.h> /* for offsetof */
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49
50 #include <windows.h>
51 #include <mmsystem.h>
52
53 #include "nt.h"
54 #include <sys/dir.h>
55 #include "ntheap.h"
56
57
58 extern Lisp_Object Vmswindows_downcase_file_names;
59 #if 0
60 extern Lisp_Object Vwin32_generate_fake_inodes;
61 #endif
62 extern Lisp_Object Vmswindows_get_true_file_attributes;
63
64 extern char *get_home_directory(void);
65
66 static char startup_dir[ MAXPATHLEN ];
67
68 /* Get the current working directory.  */
69 char *
70 getwd (char *dir)
71 {
72 #if 0
73   if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
74     return dir;
75   return NULL;
76 #else
77   /* Emacs doesn't actually change directory itself, and we want to
78      force our real wd to be where emacs.exe is to avoid unnecessary
79      conflicts when trying to rename or delete directories.  */
80   strcpy (dir, startup_dir);
81   return dir;
82 #endif
83 }
84
85 /* Emulate getloadavg.  */
86 int
87 getloadavg (double loadavg[], int nelem)
88 {
89   int i;
90
91   /* A faithful emulation is going to have to be saved for a rainy day.  */
92   for (i = 0; i < nelem; i++) 
93     {
94       loadavg[i] = 0.0;
95     }
96   return i;
97 }
98
99 /* Emulate getpwuid, getpwnam and others.  */
100
101 #define PASSWD_FIELD_SIZE 256
102
103 static char the_passwd_name[PASSWD_FIELD_SIZE];
104 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
105 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
106 static char the_passwd_dir[PASSWD_FIELD_SIZE];
107 static char the_passwd_shell[PASSWD_FIELD_SIZE];
108
109 static struct passwd the_passwd = 
110 {
111   the_passwd_name,
112   the_passwd_passwd,
113   0,
114   0,
115   0,
116   the_passwd_gecos,
117   the_passwd_dir,
118   the_passwd_shell,
119 };
120
121 int 
122 getuid () 
123
124   return the_passwd.pw_uid;
125 }
126
127 int 
128 geteuid () 
129
130   /* I could imagine arguing for checking to see whether the user is
131      in the Administrators group and returning a UID of 0 for that
132      case, but I don't know how wise that would be in the long run.  */
133   return getuid (); 
134 }
135
136 int 
137 getgid () 
138
139   return the_passwd.pw_gid;
140 }
141
142 int 
143 getegid () 
144
145   return getgid ();
146 }
147
148 struct passwd *
149 getpwuid (int uid)
150 {
151   if (uid == the_passwd.pw_uid)
152     return &the_passwd;
153   return NULL;
154 }
155
156 struct passwd *
157 getpwnam (const char *name)
158 {
159   struct passwd *pw;
160   
161   pw = getpwuid (getuid ());
162   if (!pw)
163     return pw;
164
165   if (stricmp (name, pw->pw_name))
166     return NULL;
167
168   return pw;
169 }
170
171 void
172 init_user_info ()
173 {
174   /* Find the user's real name by opening the process token and
175      looking up the name associated with the user-sid in that token.
176
177      Use the relative portion of the identifier authority value from
178      the user-sid as the user id value (same for group id using the
179      primary group sid from the process token). */
180
181   char            user_sid[256], name[256], domain[256];
182   DWORD           length = sizeof (name), dlength = sizeof (domain), trash;
183   HANDLE          token = NULL;
184   SID_NAME_USE    user_type;
185
186   if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
187       && GetTokenInformation (token, TokenUser,
188                               (PVOID) user_sid, sizeof (user_sid), &trash)
189       && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
190                            domain, &dlength, &user_type))
191     {
192       strcpy (the_passwd.pw_name, name);
193       /* Determine a reasonable uid value. */
194       if (stricmp ("administrator", name) == 0)
195         {
196           the_passwd.pw_uid = 0;
197           the_passwd.pw_gid = 0;
198         }
199       else
200         {
201           SID_IDENTIFIER_AUTHORITY * pSIA;
202
203           pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
204           /* I believe the relative portion is the last 4 bytes (of 6)
205              with msb first. */
206           the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
207                                (pSIA->Value[3] << 16) +
208                                (pSIA->Value[4] << 8)  +
209                                (pSIA->Value[5] << 0));
210           /* restrict to conventional uid range for normal users */
211           the_passwd.pw_uid = the_passwd.pw_uid % 60001;
212
213           /* Get group id */
214           if (GetTokenInformation (token, TokenPrimaryGroup,
215                                    (PVOID) user_sid, sizeof (user_sid), &trash))
216             {
217               SID_IDENTIFIER_AUTHORITY * pSIA;
218
219               pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
220               the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
221                                    (pSIA->Value[3] << 16) +
222                                    (pSIA->Value[4] << 8)  +
223                                    (pSIA->Value[5] << 0));
224               /* I don't know if this is necessary, but for safety... */
225               the_passwd.pw_gid = the_passwd.pw_gid % 60001;
226             }
227           else
228             the_passwd.pw_gid = the_passwd.pw_uid;
229         }
230     }
231   /* If security calls are not supported (presumably because we
232        are running under Windows 95), fallback to this. */
233   else if (GetUserName (name, &length))
234     {
235       strcpy (the_passwd.pw_name, name);
236       if (stricmp ("administrator", name) == 0)
237         the_passwd.pw_uid = 0;
238       else
239         the_passwd.pw_uid = 123;
240       the_passwd.pw_gid = the_passwd.pw_uid;
241     }
242   else
243     {
244       strcpy (the_passwd.pw_name, "unknown");
245       the_passwd.pw_uid = 123;
246       the_passwd.pw_gid = 123;
247     }
248
249   /* Ensure HOME and SHELL are defined. */
250 #if 0
251   /*
252    * With XEmacs, setting $HOME is deprecated.
253    */
254   if (getenv ("HOME") == NULL)
255     putenv ("HOME=c:/");
256 #endif
257   if (getenv ("SHELL") == NULL)
258     putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
259
260   /* Set dir and shell from environment variables. */
261   strcpy (the_passwd.pw_dir, get_home_directory());
262   strcpy (the_passwd.pw_shell, getenv ("SHELL"));
263
264   if (token)
265     CloseHandle (token);
266 }
267
268 /* Normalize filename by converting all path separators to
269    the specified separator.  Also conditionally convert upper
270    case path name components to lower case.  */
271
272 static void
273 normalize_filename (fp, path_sep)
274      REGISTER char *fp;
275      char path_sep;
276 {
277   char sep;
278   char *elem;
279
280   /* Always lower-case drive letters a-z, even if the filesystem
281      preserves case in filenames.
282      This is so filenames can be compared by string comparison
283      functions that are case-sensitive.  Even case-preserving filesystems
284      do not distinguish case in drive letters.  */
285   if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
286     {
287       *fp += 'a' - 'A';
288       fp += 2;
289     }
290
291   if (NILP (Vmswindows_downcase_file_names))
292     {
293       while (*fp)
294         {
295           if (*fp == '/' || *fp == '\\')
296             *fp = path_sep;
297           fp++;
298         }
299       return;
300     }
301
302   sep = path_sep;               /* convert to this path separator */
303   elem = fp;                    /* start of current path element */
304
305   do {
306     if (*fp >= 'a' && *fp <= 'z')
307       elem = 0;                 /* don't convert this element */
308
309     if (*fp == 0 || *fp == ':')
310       {
311         sep = *fp;              /* restore current separator (or 0) */
312         *fp = '/';              /* after conversion of this element */
313       }
314
315     if (*fp == '/' || *fp == '\\')
316       {
317         if (elem && elem != fp)
318           {
319             *fp = 0;            /* temporary end of string */
320             _strlwr (elem);     /* while we convert to lower case */
321           }
322         *fp = sep;              /* convert (or restore) path separator */
323         elem = fp + 1;          /* next element starts after separator */
324         sep = path_sep;
325       }
326   } while (*fp++);
327 }
328
329 /* Destructively turn backslashes into slashes.  */
330 void
331 dostounix_filename (p)
332      REGISTER char *p;
333 {
334   normalize_filename (p, '/');
335 }
336
337 /* Destructively turn slashes into backslashes.  */
338 void
339 unixtodos_filename (p)
340      REGISTER char *p;
341 {
342   normalize_filename (p, '\\');
343 }
344
345 /* Remove all CR's that are followed by a LF.
346    (From msdos.c...probably should figure out a way to share it,
347    although this code isn't going to ever change.)  */
348 int
349 crlf_to_lf (n, buf, lf_count)
350      REGISTER int n;
351      REGISTER unsigned char *buf;
352      REGISTER unsigned *lf_count;
353 {
354   unsigned char *np = buf;
355   unsigned char *startp = buf;
356   unsigned char *endp = buf + n;
357
358   if (n == 0)
359     return n;
360   while (buf < endp - 1)
361     {
362       if (*buf == 0x0a)
363         (*lf_count)++;
364       if (*buf == 0x0d)
365         {
366           if (*(++buf) != 0x0a)
367             *np++ = 0x0d;
368         }
369       else
370         *np++ = *buf++;
371     }
372   if (buf < endp)
373     {
374       if (*buf == 0x0a)
375         (*lf_count)++;
376     *np++ = *buf++;
377     }
378   return np - startp;
379 }
380
381 /* Parse the root part of file name, if present.  Return length and
382     optionally store pointer to char after root.  */
383 static int
384 parse_root (char * name, char ** pPath)
385 {
386   char * start = name;
387
388   if (name == NULL)
389     return 0;
390
391   /* find the root name of the volume if given */
392   if (isalpha (name[0]) && name[1] == ':')
393     {
394       /* skip past drive specifier */
395       name += 2;
396       if (IS_DIRECTORY_SEP (name[0]))
397         name++;
398     }
399   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
400     {
401       int slashes = 2;
402       name += 2;
403       do
404         {
405           if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
406             break;
407           name++;
408         }
409       while ( *name );
410       if (IS_DIRECTORY_SEP (name[0]))
411         name++;
412     }
413
414   if (pPath)
415     *pPath = name;
416
417   return name - start;
418 }
419
420 /* Get long base name for name; name is assumed to be absolute.  */
421 static int
422 get_long_basename (char * name, char * buf, int size)
423 {
424   WIN32_FIND_DATA find_data;
425   HANDLE dir_handle;
426   int len = 0;
427 #ifdef PIGSFLY
428   char *p;
429
430   /* If the last component of NAME has a wildcard character, 
431      return it as the basename.  */
432   p = name + strlen (name);
433   while (*p != '\\' && *p != ':' && p > name) p--;
434   if (p > name) p++;
435   if (strchr (p, '*') || strchr (p, '?'))
436     {
437       if ((len = strlen (p)) < size)
438         memcpy (buf, p, len + 1);
439       else
440         len = 0;
441       return len;
442     }
443 #endif
444
445   dir_handle = FindFirstFile (name, &find_data);
446   if (dir_handle != INVALID_HANDLE_VALUE)
447     {
448       if ((len = strlen (find_data.cFileName)) < size)
449         memcpy (buf, find_data.cFileName, len + 1);
450       else
451         len = 0;
452       FindClose (dir_handle);
453     }
454   return len;
455 }
456
457 /* Get long name for file, if possible (assumed to be absolute).  */
458 BOOL
459 win32_get_long_filename (char * name, char * buf, int size)
460 {
461   char * o = buf;
462   char * p;
463   char * q;
464   char full[ MAX_PATH ];
465   int len;
466
467   len = strlen (name);
468   if (len >= MAX_PATH)
469     return FALSE;
470
471   /* Use local copy for destructive modification.  */
472   memcpy (full, name, len+1);
473   unixtodos_filename (full);
474
475   /* Copy root part verbatim.  */
476   len = parse_root (full, &p);
477   memcpy (o, full, len);
478   o += len;
479   size -= len;
480
481   do
482     {
483       q = p;
484       p = strchr (q, '\\');
485       if (p) *p = '\0';
486       len = get_long_basename (full, o, size);
487       if (len > 0)
488         {
489           o += len;
490           size -= len;
491           if (p != NULL)
492             {
493               *p++ = '\\';
494               if (size < 2)
495                 return FALSE;
496               *o++ = '\\';
497               size--;
498               *o = '\0';
499             }
500         }
501       else
502         return FALSE;
503     }
504   while (p != NULL && *p);
505
506   return TRUE;
507 }
508
509
510 /* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
511
512 #if 0 /* #### We do not need those, do we? -kkm */
513 int 
514 unrequest_sigio (void) 
515
516   return 0;
517 }
518
519 int 
520 request_sigio (void) 
521
522   return 0;
523 }
524 #endif /* 0 */
525
526 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
527
528 LPBYTE 
529 nt_get_resource (key, lpdwtype)
530     char *key;
531     LPDWORD lpdwtype;
532 {
533   LPBYTE lpvalue;
534   HKEY hrootkey = NULL;
535   DWORD cbData;
536   BOOL ok = FALSE;
537   
538   /* Check both the current user and the local machine to see if 
539      we have any resources.  */
540   
541   if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
542     {
543       lpvalue = NULL;
544
545       if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS 
546           && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL 
547           && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
548         {
549           return (lpvalue);
550         }
551
552       if (lpvalue) xfree (lpvalue);
553         
554       RegCloseKey (hrootkey);
555     } 
556   
557   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
558     {
559       lpvalue = NULL;
560         
561       if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
562           (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
563           RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
564         {
565           return (lpvalue);
566         }
567         
568       if (lpvalue) xfree (lpvalue);
569         
570       RegCloseKey (hrootkey);
571     } 
572   
573   return (NULL);
574 }
575
576 void
577 init_environment ()
578 {
579   /* Check for environment variables and use registry if they don't exist */
580   {
581     int i;
582     LPBYTE lpval;
583     DWORD dwType;
584
585     static char * env_vars[] = 
586     {
587       "HOME",
588       "emacs_dir",
589       "EMACSLOADPATH",
590       "EMACSDEBUGPATHS",
591       "SHELL",
592       "CMDPROXY",
593       "EMACSDATA",
594       "EMACSPATH",
595       "EMACSPACKAGEPATH",
596       "EMACSLOCKDIR",
597       "INFOPATH"
598     };
599
600     for (i = 0; i < countof (env_vars); i++) 
601       {
602         if (!getenv (env_vars[i]) &&
603             (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
604           {
605             if (dwType == REG_EXPAND_SZ)
606               {
607                 char buf1[500], buf2[500];
608
609                 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
610                 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
611                 putenv (strdup (buf2));
612               }
613             else if (dwType == REG_SZ)
614               {
615                 char buf[500];
616                   
617                 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
618                 putenv (strdup (buf));
619               }
620
621             xfree (lpval);
622           }
623       }
624   }
625
626   /* Another special case: on NT, the PATH variable is actually named
627      "Path" although cmd.exe (perhaps NT itself) arranges for
628      environment variable lookup and setting to be case insensitive.
629      However, Emacs assumes a fully case sensitive environment, so we
630      need to change "Path" to "PATH" to match the expectations of
631      various elisp packages.  We do this by the sneaky method of
632      modifying the string in the C runtime environ entry.
633
634      The same applies to COMSPEC.  */
635   {
636     char ** envp;
637
638     for (envp = environ; *envp; envp++)
639       if (_strnicmp (*envp, "PATH=", 5) == 0)
640         memcpy (*envp, "PATH=", 5);
641       else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
642         memcpy (*envp, "COMSPEC=", 8);
643   }
644
645   /* Remember the initial working directory for getwd, then make the
646      real wd be the location of emacs.exe to avoid conflicts when
647      renaming or deleting directories.  (We also don't call chdir when
648      running subprocesses for the same reason.)  */
649   if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
650     abort ();
651
652   {
653     char *p;
654     char modname[MAX_PATH];
655
656     if (!GetModuleFileName (NULL, modname, MAX_PATH))
657       abort ();
658     if ((p = strrchr (modname, '\\')) == NULL)
659       abort ();
660     *p = 0;
661
662     SetCurrentDirectory (modname);
663   }
664
665   init_user_info ();
666 }
667
668 #ifndef HAVE_X_WINDOWS
669 /* X11R6 on NT provides the single parameter version of this command. */
670
671 #include <sys/timeb.h>
672
673 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
674 void 
675 gettimeofday (struct timeval *tv, struct timezone *tz)
676 {
677   struct _timeb tb;
678   _ftime (&tb);
679
680   tv->tv_sec = tb.time;
681   tv->tv_usec = tb.millitm * 1000L;
682   if (tz) 
683     {
684       tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich  */
685       tz->tz_dsttime = tb.dstflag;      /* type of dst correction  */
686     }
687 }
688
689 #endif /* HAVE_X_WINDOWS */
690
691 /* ------------------------------------------------------------------------- */
692 /* IO support and wrapper functions for Win32 API. */
693 /* ------------------------------------------------------------------------- */
694
695 /* Place a wrapper around the MSVC version of ctime.  It returns NULL
696    on network directories, so we handle that case here.  
697    (Ulrich Leodolter, 1/11/95).  */
698 char *
699 sys_ctime (const time_t *t)
700 {
701   char *str = (char *) ctime (t);
702   return (str ? str : "Sun Jan 01 00:00:00 1970");
703 }
704
705 /* Emulate sleep...we could have done this with a define, but that
706    would necessitate including windows.h in the files that used it.
707    This is much easier.  */
708
709 #ifndef HAVE_X_WINDOWS
710 void
711 sys_sleep (int seconds)
712 {
713   Sleep (seconds * 1000);
714 }
715 #endif
716
717 /* #### This is an evil dirty hack. We must get rid of it.
718    Word "munging" is not in XEmacs lexicon. - kkm */
719
720 /* Internal MSVC data and functions for low-level descriptor munging */
721 #if (_MSC_VER == 900)
722 extern char _osfile[];
723 #endif
724 extern int __cdecl _set_osfhnd (int fd, long h);
725 extern int __cdecl _free_osfhnd (int fd);
726
727 /* parallel array of private info on file handles */
728 filedesc fd_info [ MAXDESC ];
729
730 typedef struct volume_info_data {
731   struct volume_info_data * next;
732
733   /* time when info was obtained */
734   DWORD     timestamp;
735
736   /* actual volume info */
737   char *    root_dir;
738   DWORD     serialnum;
739   DWORD     maxcomp;
740   DWORD     flags;
741   char *    name;
742   char *    type;
743 } volume_info_data;
744
745 /* Global referenced by various functions.  */
746 static volume_info_data volume_info;
747
748 /* Vector to indicate which drives are local and fixed (for which cached
749    data never expires).  */
750 static BOOL fixed_drives[26];
751
752 /* Consider cached volume information to be stale if older than 10s,
753    at least for non-local drives.  Info for fixed drives is never stale.  */
754 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
755 #define VOLINFO_STILL_VALID( root_dir, info )           \
756   ( ( isalpha (root_dir[0]) &&                          \
757       fixed_drives[ DRIVE_INDEX (root_dir[0]) ] )       \
758     || GetTickCount () - info->timestamp < 10000 )
759
760 /* Cache support functions.  */
761
762 /* Simple linked list with linear search is sufficient.  */
763 static volume_info_data *volume_cache = NULL;
764
765 static volume_info_data *
766 lookup_volume_info (char * root_dir)
767 {
768   volume_info_data * info;
769
770   for (info = volume_cache; info; info = info->next)
771     if (stricmp (info->root_dir, root_dir) == 0)
772       break;
773   return info;
774 }
775
776 static void
777 add_volume_info (char * root_dir, volume_info_data * info)
778 {
779   info->root_dir = xstrdup (root_dir);
780   info->next = volume_cache;
781   volume_cache = info;
782 }
783
784
785 /* Wrapper for GetVolumeInformation, which uses caching to avoid
786    performance penalty (~2ms on 486 for local drives, 7.5ms for local
787    cdrom drive, ~5-10ms or more for remote drives on LAN).  */
788 volume_info_data *
789 GetCachedVolumeInformation (char * root_dir)
790 {
791   volume_info_data * info;
792   char default_root[ MAX_PATH ];
793
794   /* NULL for root_dir means use root from current directory.  */
795   if (root_dir == NULL)
796     {
797       if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
798         return NULL;
799       parse_root (default_root, &root_dir);
800       *root_dir = 0;
801       root_dir = default_root;
802     }
803
804   /* Local fixed drives can be cached permanently.  Removable drives
805      cannot be cached permanently, since the volume name and serial
806      number (if nothing else) can change.  Remote drives should be
807      treated as if they are removable, since there is no sure way to
808      tell whether they are or not.  Also, the UNC association of drive
809      letters mapped to remote volumes can be changed at any time (even
810      by other processes) without notice.
811    
812      As a compromise, so we can benefit from caching info for remote
813      volumes, we use a simple expiry mechanism to invalidate cache
814      entries that are more than ten seconds old.  */
815
816 #if 0
817   /* No point doing this, because WNetGetConnection is even slower than
818      GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
819      GetDriveType is about the only call of this type which does not
820      involve network access, and so is extremely quick).  */
821
822   /* Map drive letter to UNC if remote. */
823   if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
824     {
825       char remote_name[ 256 ];
826       char drive[3] = { root_dir[0], ':' };
827
828       if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
829           == NO_ERROR)
830         /* do something */ ;
831     }
832 #endif
833
834   info = lookup_volume_info (root_dir);
835
836   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
837   {
838     char  name[ 256 ];
839   DWORD     serialnum;
840   DWORD     maxcomp;
841   DWORD     flags;
842     char  type[ 256 ];
843
844     /* Info is not cached, or is stale. */
845     if (!GetVolumeInformation (root_dir,
846                                name, sizeof (name),
847                                &serialnum,
848                                &maxcomp,
849                                &flags,
850                                type, sizeof (type)))
851       return NULL;
852
853     /* Cache the volume information for future use, overwriting existing
854        entry if present.  */
855     if (info == NULL)
856       {
857         info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
858         add_volume_info (root_dir, info);
859       }
860     else
861       {
862         free (info->name);
863         free (info->type);
864       }
865
866     info->name = xstrdup (name);
867     info->serialnum = serialnum;
868     info->maxcomp = maxcomp;
869     info->flags = flags;
870     info->type = xstrdup (type);
871     info->timestamp = GetTickCount ();
872   }
873
874   return info;
875 }
876
877 /* Get information on the volume where name is held; set path pointer to
878    start of pathname in name (past UNC header\volume header if present).  */
879 int
880 get_volume_info (const char * name, const char ** pPath)
881 {
882   char temp[MAX_PATH];
883   char *rootname = NULL;  /* default to current volume */
884   volume_info_data * info;
885
886   if (name == NULL)
887     return FALSE;
888
889   /* find the root name of the volume if given */
890   if (isalpha (name[0]) && name[1] == ':')
891     {
892       rootname = temp;
893       temp[0] = *name++;
894       temp[1] = *name++;
895       temp[2] = '\\';
896       temp[3] = 0;
897     }
898   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
899     {
900       char *str = temp;
901       int slashes = 4;
902       rootname = temp;
903       do
904         {
905           if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
906             break;
907           *str++ = *name++;
908         }
909       while ( *name );
910
911       *str++ = '\\';
912       *str = 0;
913     }
914
915   if (pPath)
916     *pPath = name;
917     
918   info = GetCachedVolumeInformation (rootname);
919   if (info != NULL)
920     {
921       /* Set global referenced by other functions.  */
922       volume_info = *info;
923       return TRUE;
924     }
925   return FALSE;
926 }
927
928 /* Determine if volume is FAT format (ie. only supports short 8.3
929    names); also set path pointer to start of pathname in name.  */
930 int
931 is_fat_volume (const char * name, const char ** pPath)
932 {
933   if (get_volume_info (name, pPath))
934     return (volume_info.maxcomp == 12);
935   return FALSE;
936 }
937
938 /* Map filename to a legal 8.3 name if necessary. */
939 const char *
940 map_win32_filename (const char * name, const char ** pPath)
941 {
942   static char shortname[MAX_PATH];
943   char * str = shortname;
944   char c;
945   char * path;
946   const char * save_name = name;
947
948   if (is_fat_volume (name, &path)) /* truncate to 8.3 */
949     {
950       REGISTER int left = 8;    /* maximum number of chars in part */
951       REGISTER int extn = 0;    /* extension added? */
952       REGISTER int dots = 2;    /* maximum number of dots allowed */
953
954       while (name < path)
955         *str++ = *name++;       /* skip past UNC header */
956
957       while ((c = *name++))
958         {
959           switch ( c )
960             {
961             case '\\':
962             case '/':
963               *str++ = '\\';
964               extn = 0;         /* reset extension flags */
965               dots = 2;         /* max 2 dots */
966               left = 8;         /* max length 8 for main part */
967               break;
968             case ':':
969               *str++ = ':';
970               extn = 0;         /* reset extension flags */
971               dots = 2;         /* max 2 dots */
972               left = 8;         /* max length 8 for main part */
973               break;
974             case '.':
975               if ( dots )
976                 {
977                   /* Convert path components of the form .xxx to _xxx,
978                      but leave . and .. as they are.  This allows .emacs
979                      to be read as _emacs, for example.  */
980
981                   if (! *name ||
982                       *name == '.' ||
983                       IS_DIRECTORY_SEP (*name))
984                     {
985                       *str++ = '.';
986                       dots--;
987                     }
988                   else
989                     {
990                       *str++ = '_';
991                       left--;
992                       dots = 0;
993                     }
994                 }
995               else if ( !extn )
996                 {
997                   *str++ = '.';
998                   extn = 1;             /* we've got an extension */
999                   left = 3;             /* 3 chars in extension */
1000                 }
1001               else
1002                 {
1003                   /* any embedded dots after the first are converted to _ */
1004                   *str++ = '_';
1005                 }
1006               break;
1007             case '~':
1008             case '#':                   /* don't lose these, they're important */
1009               if ( ! left )
1010                 str[-1] = c;            /* replace last character of part */
1011               /* FALLTHRU */
1012             default:
1013               if ( left )
1014                 {
1015                   *str++ = tolower (c); /* map to lower case (looks nicer) */
1016                   left--;
1017                   dots = 0;             /* started a path component */
1018                 }
1019               break;
1020             }
1021         }
1022       *str = '\0';
1023     }
1024   else
1025     {
1026       strcpy (shortname, name);
1027       unixtodos_filename (shortname);
1028     }
1029
1030   if (pPath)
1031     *pPath = shortname + (path - save_name);
1032
1033   return shortname;
1034 }
1035
1036
1037 /* Emulate the Unix directory procedures opendir, closedir, 
1038    and readdir.  We can't use the procedures supplied in sysdep.c,
1039    so we provide them here.  */
1040
1041 struct direct dir_static;       /* simulated directory contents */
1042 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1043 static int    dir_is_fat;
1044 static char   dir_pathname[MAXPATHLEN+1];
1045 static WIN32_FIND_DATA dir_find_data;
1046
1047 DIR *
1048 opendir (const char *filename)
1049 {
1050   DIR *dirp;
1051
1052   /* Opening is done by FindFirstFile.  However, a read is inherent to
1053      this operation, so we defer the open until read time.  */
1054
1055   if (!(dirp = (DIR *) xmalloc (sizeof (DIR))))
1056     return NULL;
1057   if (dir_find_handle != INVALID_HANDLE_VALUE)
1058     return NULL;
1059
1060   dirp->dd_fd = 0;
1061   dirp->dd_loc = 0;
1062   dirp->dd_size = 0;
1063
1064   strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1065   dir_pathname[MAXPATHLEN] = '\0';
1066   dir_is_fat = is_fat_volume (filename, NULL);
1067
1068   return dirp;
1069 }
1070
1071 void
1072 closedir (DIR *dirp)
1073 {
1074   /* If we have a find-handle open, close it.  */
1075   if (dir_find_handle != INVALID_HANDLE_VALUE)
1076     {
1077       FindClose (dir_find_handle);
1078       dir_find_handle = INVALID_HANDLE_VALUE;
1079     }
1080   xfree ((char *) dirp);
1081 }
1082
1083 struct direct *
1084 readdir (DIR *dirp)
1085 {
1086   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1087   if (dir_find_handle == INVALID_HANDLE_VALUE)
1088     {
1089       char filename[MAXNAMLEN + 3];
1090       int ln;
1091
1092       strcpy (filename, dir_pathname);
1093       ln = strlen (filename) - 1;
1094       if (!IS_DIRECTORY_SEP (filename[ln]))
1095         strcat (filename, "\\");
1096       strcat (filename, "*");
1097
1098       dir_find_handle = FindFirstFile (filename, &dir_find_data);
1099
1100       if (dir_find_handle == INVALID_HANDLE_VALUE)
1101         return NULL;
1102     }
1103   else
1104     {
1105       if (!FindNextFile (dir_find_handle, &dir_find_data))
1106         return NULL;
1107     }
1108   
1109   /* Emacs never uses this value, so don't bother making it match
1110      value returned by stat().  */
1111   dir_static.d_ino = 1;
1112   
1113   dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1114     dir_static.d_namlen - dir_static.d_namlen % 4;
1115   
1116   dir_static.d_namlen = strlen (dir_find_data.cFileName);
1117   strcpy (dir_static.d_name, dir_find_data.cFileName);
1118   if (dir_is_fat)
1119     _strlwr (dir_static.d_name);
1120   else if (!NILP (Vmswindows_downcase_file_names))
1121     {
1122       REGISTER char *p;
1123       for (p = dir_static.d_name; *p; p++)
1124         if (*p >= 'a' && *p <= 'z')
1125           break;
1126       if (!*p)
1127         _strlwr (dir_static.d_name);
1128     }
1129   
1130   return &dir_static;
1131 }
1132
1133 #if 0
1134 /* #### Have to check if all that sad story about '95 is true - kkm */
1135 int
1136 sys_rename (const char * oldname, const char * newname)
1137 {
1138   char temp[MAX_PATH];
1139   DWORD attr;
1140
1141   /* MoveFile on Win95 doesn't correctly change the short file name
1142      alias in a number of circumstances (it is not easy to predict when
1143      just by looking at oldname and newname, unfortunately).  In these
1144      cases, renaming through a temporary name avoids the problem.
1145
1146      A second problem on Win95 is that renaming through a temp name when
1147      newname is uppercase fails (the final long name ends up in
1148      lowercase, although the short alias might be uppercase) UNLESS the
1149      long temp name is not 8.3.
1150
1151      So, on Win95 we always rename through a temp name, and we make sure
1152      the temp name has a long extension to ensure correct renaming.  */
1153
1154   strcpy (temp, map_win32_filename (oldname, NULL));
1155
1156   if (GetVersion () & 0x80000000)
1157     {
1158       char * p;
1159
1160       if (p = strrchr (temp, '\\'))
1161         p++;
1162       else
1163         p = temp;
1164       /* Force temp name to require a manufactured 8.3 alias - this
1165          seems to make the second rename work properly. */
1166       strcpy (p, "_rename_temp.XXXXXX");
1167       sys_mktemp (temp);
1168       if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1169         return -1;
1170     }
1171
1172   /* Emulate Unix behaviour - newname is deleted if it already exists
1173      (at least if it is a file; don't do this for directories).
1174      However, don't do this if we are just changing the case of the file
1175      name - we will end up deleting the file we are trying to rename!  */
1176   newname = map_win32_filename (newname, NULL);
1177
1178   /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1179      do not refer to the same file, eg. through share aliases.  */
1180   if (stricmp (newname, temp) != 0
1181       && (attr = GetFileAttributes (newname)) != -1
1182       && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1183     {
1184       _chmod (newname, 0666);
1185       _unlink (newname);
1186     }
1187
1188   return rename (temp, newname);
1189 }
1190 #endif /* 0 */
1191
1192 static FILETIME utc_base_ft;
1193 static long double utc_base;
1194 static int init = 0;
1195
1196 time_t
1197 convert_time (FILETIME ft)
1198 {
1199   long double ret;
1200
1201   if (!init)
1202     {
1203       /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1204       SYSTEMTIME st;
1205
1206       st.wYear = 1970;
1207       st.wMonth = 1;
1208       st.wDay = 1;
1209       st.wHour = 0;
1210       st.wMinute = 0;
1211       st.wSecond = 0;
1212       st.wMilliseconds = 0;
1213
1214       SystemTimeToFileTime (&st, &utc_base_ft);
1215       utc_base = (long double) utc_base_ft.dwHighDateTime
1216         * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1217       init = 1;
1218     }
1219
1220   if (CompareFileTime (&ft, &utc_base_ft) < 0)
1221     return 0;
1222
1223   ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1224   ret -= utc_base;
1225   return (time_t) (ret * 1e-7);
1226 }
1227
1228 #if 0
1229 /* in case we ever have need of this */
1230 void
1231 convert_from_time_t (time_t time, FILETIME * pft)
1232 {
1233   long double tmp;
1234
1235   if (!init)
1236     {
1237       /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1238       SYSTEMTIME st;
1239
1240       st.wYear = 1970;
1241       st.wMonth = 1;
1242       st.wDay = 1;
1243       st.wHour = 0;
1244       st.wMinute = 0;
1245       st.wSecond = 0;
1246       st.wMilliseconds = 0;
1247
1248       SystemTimeToFileTime (&st, &utc_base_ft);
1249       utc_base = (long double) utc_base_ft.dwHighDateTime
1250         * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1251       init = 1;
1252     }
1253
1254   /* time in 100ns units since 1-Jan-1601 */
1255   tmp = (long double) time * 1e7 + utc_base;
1256   pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1257   pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1258 }
1259 #endif
1260
1261 #if 0
1262 /* No reason to keep this; faking inode values either by hashing or even
1263    using the file index from GetInformationByHandle, is not perfect and
1264    so by default Emacs doesn't use the inode values on Windows.
1265    Instead, we now determine file-truename correctly (except for
1266    possible drive aliasing etc).  */
1267
1268 /*  Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1269 static unsigned
1270 hashval (const unsigned char * str)
1271 {
1272   unsigned h = 0;
1273   while (*str)
1274     {
1275       h = (h << 4) + *str++;
1276       h ^= (h >> 28);
1277     }
1278   return h;
1279 }
1280
1281 /* Return the hash value of the canonical pathname, excluding the
1282    drive/UNC header, to get a hopefully unique inode number. */
1283 static DWORD
1284 generate_inode_val (const char * name)
1285 {
1286   char fullname[ MAX_PATH ];
1287   char * p;
1288   unsigned hash;
1289
1290   /* Get the truly canonical filename, if it exists.  (Note: this
1291      doesn't resolve aliasing due to subst commands, or recognise hard
1292      links.  */
1293   if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1294     abort ();
1295
1296   parse_root (fullname, &p);
1297   /* Normal Win32 filesystems are still case insensitive. */
1298   _strlwr (p);
1299   return hashval (p);
1300 }
1301
1302 #endif
1303
1304 /* MSVC stat function can't cope with UNC names and has other bugs, so
1305    replace it with our own.  This also allows us to calculate consistent
1306    inode values without hacks in the main Emacs code. */
1307 int
1308 stat (const char * path, struct stat * buf)
1309 {
1310   char * name;
1311   WIN32_FIND_DATA wfd;
1312   HANDLE fh;
1313   DWORD fake_inode;
1314   int permission;
1315   int len;
1316   int rootdir = FALSE;
1317
1318   if (path == NULL || buf == NULL)
1319     {
1320       errno = EFAULT;
1321       return -1;
1322     }
1323
1324   name = (char *) map_win32_filename (path, &path);
1325   /* must be valid filename, no wild cards */
1326   if (strchr (name, '*') || strchr (name, '?'))
1327     {
1328       errno = ENOENT;
1329       return -1;
1330     }
1331
1332   /* Remove trailing directory separator, unless name is the root
1333      directory of a drive or UNC volume in which case ensure there
1334      is a trailing separator. */
1335   len = strlen (name);
1336   rootdir = (path >= name + len - 1
1337              && (IS_DIRECTORY_SEP (*path) || *path == 0));
1338   name = strcpy (alloca (len + 2), name);
1339
1340   if (rootdir)
1341     {
1342       if (!IS_DIRECTORY_SEP (name[len-1]))
1343         strcat (name, "\\");
1344       if (GetDriveType (name) < 2)
1345         {
1346           errno = ENOENT;
1347           return -1;
1348         }
1349       memset (&wfd, 0, sizeof (wfd));
1350       wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1351       wfd.ftCreationTime = utc_base_ft;
1352       wfd.ftLastAccessTime = utc_base_ft;
1353       wfd.ftLastWriteTime = utc_base_ft;
1354       strcpy (wfd.cFileName, name);
1355     }
1356   else
1357     {
1358       if (IS_DIRECTORY_SEP (name[len-1]))
1359         name[len - 1] = 0;
1360
1361       /* (This is hacky, but helps when doing file completions on
1362          network drives.)  Optimize by using information available from
1363          active readdir if possible.  */
1364       if (dir_find_handle != INVALID_HANDLE_VALUE &&
1365           (len = strlen (dir_pathname)),
1366           strnicmp (name, dir_pathname, len) == 0 &&
1367           IS_DIRECTORY_SEP (name[len]) &&
1368           stricmp (name + len + 1, dir_static.d_name) == 0)
1369         {
1370           /* This was the last entry returned by readdir.  */
1371           wfd = dir_find_data;
1372         }
1373       else
1374         {
1375       fh = FindFirstFile (name, &wfd);
1376       if (fh == INVALID_HANDLE_VALUE)
1377         {
1378           errno = ENOENT;
1379           return -1;
1380         }
1381       FindClose (fh);
1382     }
1383     }
1384
1385   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1386     {
1387       buf->st_mode = _S_IFDIR;
1388       buf->st_nlink = 2;        /* doesn't really matter */
1389       fake_inode = 0;           /* this doesn't either I think */
1390     }
1391   else if (!NILP (Vmswindows_get_true_file_attributes))
1392     {
1393       /* This is more accurate in terms of gettting the correct number
1394          of links, but is quite slow (it is noticable when Emacs is
1395          making a list of file name completions). */
1396       BY_HANDLE_FILE_INFORMATION info;
1397
1398       /* No access rights required to get info.  */
1399       fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1400                        OPEN_EXISTING, 0, NULL);
1401
1402       if (GetFileInformationByHandle (fh, &info))
1403         {
1404           switch (GetFileType (fh))
1405             {
1406             case FILE_TYPE_DISK:
1407               buf->st_mode = _S_IFREG;
1408               break;
1409             case FILE_TYPE_PIPE:
1410               buf->st_mode = _S_IFIFO;
1411               break;
1412             case FILE_TYPE_CHAR:
1413             case FILE_TYPE_UNKNOWN:
1414             default:
1415               buf->st_mode = _S_IFCHR;
1416             }
1417           buf->st_nlink = (short) info.nNumberOfLinks;
1418           /* Might as well use file index to fake inode values, but this
1419              is not guaranteed to be unique unless we keep a handle open
1420              all the time (even then there are situations where it is
1421              not unique).  Reputedly, there are at most 48 bits of info
1422              (on NTFS, presumably less on FAT). */
1423           fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1424           CloseHandle (fh);
1425         }
1426       else
1427         {
1428           errno = EACCES;
1429           return -1;
1430         }
1431     }
1432   else
1433     {
1434       /* Don't bother to make this information more accurate.  */
1435       buf->st_mode = _S_IFREG;
1436       buf->st_nlink = 1;
1437       fake_inode = 0;
1438     }
1439
1440 #if 0
1441   /* Not sure if there is any point in this.  */
1442   if (!NILP (Vwin32_generate_fake_inodes))
1443     fake_inode = generate_inode_val (name);
1444   else if (fake_inode == 0)
1445     {
1446       /* For want of something better, try to make everything unique.  */
1447       static DWORD gen_num = 0;
1448       fake_inode = ++gen_num;
1449     }
1450 #endif
1451
1452   /* #### MSVC defines _ino_t to be short; other libc's might not.  */
1453   buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1454
1455   /* consider files to belong to current user */
1456   buf->st_uid = the_passwd.pw_uid;
1457   buf->st_gid = the_passwd.pw_gid;
1458
1459   /* volume_info is set indirectly by map_win32_filename */
1460   buf->st_dev = volume_info.serialnum;
1461   buf->st_rdev = volume_info.serialnum;
1462
1463
1464   buf->st_size = wfd.nFileSizeLow;
1465
1466   /* Convert timestamps to Unix format. */
1467   buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1468   buf->st_atime = convert_time (wfd.ftLastAccessTime);
1469   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1470   buf->st_ctime = convert_time (wfd.ftCreationTime);
1471   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1472
1473   /* determine rwx permissions */
1474   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1475     permission = _S_IREAD;
1476   else
1477     permission = _S_IREAD | _S_IWRITE;
1478   
1479   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1480     permission |= _S_IEXEC;
1481   else
1482     {
1483       char * p = strrchr (name, '.');
1484       if (p != NULL &&
1485           (stricmp (p, ".exe") == 0 ||
1486            stricmp (p, ".com") == 0 ||
1487            stricmp (p, ".bat") == 0 ||
1488            stricmp (p, ".cmd") == 0))
1489         permission |= _S_IEXEC;
1490     }
1491
1492   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1493
1494   return 0;
1495 }
1496
1497 /* From callproc.c  */
1498 extern Lisp_Object Vbinary_process_input;
1499 extern Lisp_Object Vbinary_process_output;
1500
1501 /* Unix pipe() has only one arg */
1502 int
1503 sys_pipe (int * phandles)
1504 {
1505   int rc;
1506   unsigned flags;
1507
1508   /* make pipe handles non-inheritable; when we spawn a child, we
1509      replace the relevant handle with an inheritable one.  Also put
1510      pipes into binary mode; we will do text mode translation ourselves
1511      if required.  */
1512   rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1513
1514   if (rc == 0)
1515     {
1516       flags = FILE_PIPE | FILE_READ;
1517       if (!NILP (Vbinary_process_output))
1518           flags |= FILE_BINARY;
1519       fd_info[phandles[0]].flags = flags;
1520
1521       flags = FILE_PIPE | FILE_WRITE;
1522       if (!NILP (Vbinary_process_input))
1523           flags |= FILE_BINARY;
1524       fd_info[phandles[1]].flags = flags;
1525     }
1526
1527   return rc;
1528 }
1529
1530 /* From ntproc.c */
1531 extern Lisp_Object Vwin32_pipe_read_delay;
1532
1533 /* Function to do blocking read of one byte, needed to implement
1534    select.  It is only allowed on sockets and pipes. */
1535 int
1536 _sys_read_ahead (int fd)
1537 {
1538   child_process * cp;
1539   int rc;
1540
1541   if (fd < 0 || fd >= MAXDESC)
1542     return STATUS_READ_ERROR;
1543
1544   cp = fd_info[fd].cp;
1545
1546   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
1547     return STATUS_READ_ERROR;
1548
1549   if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
1550       || (fd_info[fd].flags & FILE_READ) == 0)
1551     {
1552       /* fd is not a pipe or socket */
1553       abort ();
1554     }
1555   
1556   cp->status = STATUS_READ_IN_PROGRESS;
1557   
1558   if (fd_info[fd].flags & FILE_PIPE)
1559     {
1560       rc = _read (fd, &cp->chr, sizeof (char));
1561
1562       /* Give subprocess time to buffer some more output for us before
1563          reporting that input is available; we need this because Win95
1564          connects DOS programs to pipes by making the pipe appear to be
1565          the normal console stdout - as a result most DOS programs will
1566          write to stdout without buffering, ie.  one character at a
1567          time.  Even some Win32 programs do this - "dir" in a command
1568          shell on NT is very slow if we don't do this. */
1569       if (rc > 0)
1570         {
1571           int wait = XINT (Vwin32_pipe_read_delay);
1572
1573           if (wait > 0)
1574             Sleep (wait);
1575           else if (wait < 0)
1576             while (++wait <= 0)
1577               /* Yield remainder of our time slice, effectively giving a
1578                  temporary priority boost to the child process. */
1579               Sleep (0);
1580         }
1581     }
1582
1583   if (rc == sizeof (char))
1584     cp->status = STATUS_READ_SUCCEEDED;
1585   else
1586     cp->status = STATUS_READ_FAILED;
1587
1588   return cp->status;
1589 }
1590
1591 void
1592 term_ntproc (int unused)
1593 {
1594 }
1595
1596 void
1597 init_ntproc ()
1598 {
1599   /* Initial preparation for subprocess support: replace our standard
1600      handles with non-inheritable versions. */
1601   {
1602     HANDLE parent;
1603     HANDLE stdin_save =  INVALID_HANDLE_VALUE;
1604     HANDLE stdout_save = INVALID_HANDLE_VALUE;
1605     HANDLE stderr_save = INVALID_HANDLE_VALUE;
1606
1607     parent = GetCurrentProcess ();
1608
1609     /* ignore errors when duplicating and closing; typically the
1610        handles will be invalid when running as a gui program. */
1611     DuplicateHandle (parent, 
1612                      GetStdHandle (STD_INPUT_HANDLE), 
1613                      parent,
1614                      &stdin_save, 
1615                      0, 
1616                      FALSE, 
1617                      DUPLICATE_SAME_ACCESS);
1618     
1619     DuplicateHandle (parent,
1620                      GetStdHandle (STD_OUTPUT_HANDLE),
1621                      parent,
1622                      &stdout_save,
1623                      0,
1624                      FALSE,
1625                      DUPLICATE_SAME_ACCESS);
1626     
1627     DuplicateHandle (parent,
1628                      GetStdHandle (STD_ERROR_HANDLE),
1629                      parent,
1630                      &stderr_save,
1631                      0,
1632                      FALSE,
1633                      DUPLICATE_SAME_ACCESS);
1634     
1635     fclose (stdin);
1636     fclose (stdout);
1637     fclose (stderr);
1638
1639     if (stdin_save != INVALID_HANDLE_VALUE)
1640       _open_osfhandle ((long) stdin_save, O_TEXT);
1641     else
1642       _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1643     _fdopen (0, "r");
1644
1645     if (stdout_save != INVALID_HANDLE_VALUE)
1646       _open_osfhandle ((long) stdout_save, O_TEXT);
1647     else
1648       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1649     _fdopen (1, "w");
1650
1651     if (stderr_save != INVALID_HANDLE_VALUE)
1652       _open_osfhandle ((long) stderr_save, O_TEXT);
1653     else
1654       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1655     _fdopen (2, "w");
1656   }
1657
1658   /* unfortunately, atexit depends on implementation of malloc */
1659   /* atexit (term_ntproc); */
1660   signal (SIGABRT, term_ntproc);
1661
1662   /* determine which drives are fixed, for GetCachedVolumeInformation */
1663   {
1664     /* GetDriveType must have trailing backslash. */
1665     char drive[] = "A:\\";
1666
1667     /* Loop over all possible drive letters */
1668     while ( *drive <= 'Z' )
1669     {
1670       /* Record if this drive letter refers to a fixed drive. */
1671       fixed_drives[ DRIVE_INDEX (*drive) ] =
1672         (GetDriveType (drive) == DRIVE_FIXED);
1673
1674       (*drive)++;
1675     }
1676   }
1677 }
1678 #ifndef HAVE_TTY
1679 Lisp_Object
1680 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1681                                           Error_behavior errb)
1682 {
1683   return Vstdio_str;
1684 }
1685
1686 Lisp_Object
1687 tty_canonicalize_console_connection (Lisp_Object connection,
1688                                      Error_behavior errb)
1689 {
1690   return Vstdio_str;
1691 }
1692
1693 Lisp_Object
1694 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1695                                          Error_behavior errb)
1696 {
1697   return Vstdio_str;
1698 }
1699
1700 Lisp_Object
1701 tty_canonicalize_device_connection (Lisp_Object connection,
1702                                     Error_behavior errb)
1703 {
1704   return Vstdio_str;
1705 }
1706 #endif
1707
1708 /*--------------------------------------------------------------------*/
1709 /* Signal support                                                     */
1710 /*--------------------------------------------------------------------*/
1711
1712 /* We need MS-defined signal and raise here */
1713 #undef signal
1714 #undef raise
1715
1716 #define sigmask(nsig) (1U << nsig)
1717
1718 /* We can support as many signals as fit into word */
1719 #define SIG_MAX 32
1720
1721 /* Signal handlers. Initial value = 0 = SIG_DFL */
1722 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1723
1724 /* Signal block mask: bit set to 1 means blocked */
1725 unsigned signal_block_mask = 0;
1726
1727 /* Signal pending mask: bit set to 1 means sig is pending */
1728 unsigned signal_pending_mask = 0;
1729
1730 msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
1731 {
1732   /* We delegate some signals to the system function */
1733   if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1734     return signal (nsig, handler);
1735
1736   if (nsig < 0 || nsig > SIG_MAX)
1737     {
1738       errno = EINVAL;
1739       return NULL;
1740     }
1741
1742   /* Store handler ptr */
1743   {
1744     msw_sighandler old_handler = signal_handlers[nsig];
1745     signal_handlers[nsig] = handler;
1746     return old_handler;
1747   }
1748 }
1749   
1750 int msw_sighold (int nsig)
1751 {
1752   if (nsig < 0 || nsig > SIG_MAX)
1753     return errno = EINVAL;
1754
1755   signal_block_mask |= sigmask(nsig);
1756   return 0;
1757 }
1758
1759 int msw_sigrelse (int nsig)
1760 {
1761   if (nsig < 0 || nsig > SIG_MAX)
1762     return errno = EINVAL;
1763
1764   signal_block_mask &= ~sigmask(nsig);
1765
1766   if (signal_pending_mask & sigmask(nsig))
1767     msw_raise (nsig);
1768
1769   return 0;
1770 }
1771
1772 int msw_sigpause (int nsig)
1773 {
1774   /* This is currently not called, because the only
1775      call to sigpause inside XEmacs is with SIGCHLD
1776      parameter. Just in case, we put an assert here,
1777      so anyone who will add a call to sigpause will
1778      be surprised (or surprise someone else...) */
1779   assert (0);
1780   return 0;
1781 }
1782
1783 int msw_raise (int nsig)
1784 {
1785   /* We delegate some raises to the system routine */
1786   if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1787     return raise (nsig);
1788
1789   if (nsig < 0 || nsig > SIG_MAX)
1790     return errno = EINVAL;
1791
1792   /* If the signal is blocked, remember to issue later */
1793   if (signal_block_mask & sigmask(nsig))
1794     {
1795       signal_pending_mask |= sigmask(nsig);
1796       return 0;
1797     }
1798
1799   if (signal_handlers[nsig] == SIG_IGN)
1800     return 0;
1801
1802   if (signal_handlers[nsig] != SIG_DFL)
1803     {
1804       (*signal_handlers[nsig])(nsig);
1805       return 0;
1806     }
1807
1808   /* Default signal actions */
1809   if (nsig == SIGALRM || nsig == SIGPROF)
1810     exit (3);
1811
1812   /* Other signals are ignored by default */
1813 }
1814
1815 /*--------------------------------------------------------------------*/
1816 /* Async timers                                                       */
1817 /*--------------------------------------------------------------------*/
1818
1819 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1820
1821    itimerproc() function has an implementation limitation: it does
1822    not allow to set *both* interval and period. If an attempt is
1823    made to set both, and then they are unequal, the function
1824    asserts.
1825
1826    Minimum timer resolution on Win32 systems varies, and is greater
1827    than or equal than 1 ms. The resolution is always wrapped not to
1828    attempt to get below the system defined limit.
1829    */
1830
1831 /* Timer precision, denominator of one fraction: for 100 ms
1832    interval, request 10 ms precision
1833    */
1834 const int timer_prec = 10;
1835
1836 /* Last itimevals, as set by calls to setitimer */
1837 static struct itimerval it_alarm;
1838 static struct itimerval it_prof;
1839
1840 /* Timer IDs as returned by MM */
1841 MMRESULT tid_alarm = 0;
1842 MMRESULT tid_prof = 0;
1843
1844 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1845                                  DWORD dw1, DWORD dw2)
1846 {
1847   /* Just raise a signal indicated by dwUser parameter */
1848   msw_raise (dwUser);
1849 }
1850
1851 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1852    if division results in zero */
1853 static UINT period (const struct itimerval* it, UINT denom)
1854 {
1855   static TIMECAPS time_caps;
1856
1857   UINT res;
1858   const struct timeval* tv = 
1859     (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1860     ? &it->it_interval : &it->it_value;
1861   
1862   /* Zero means stop timer */
1863   if (tv->tv_sec == 0 && tv->tv_usec == 0)
1864     return 0;
1865   
1866   /* Conver to ms and divide by denom */
1867   res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1868   
1869   /* Converge to minimum timer resolution */
1870   if (time_caps.wPeriodMin == 0)
1871       timeGetDevCaps (&time_caps, sizeof(time_caps));
1872
1873   if (res < time_caps.wPeriodMin)
1874     res = time_caps.wPeriodMin;
1875
1876   return res;
1877 }
1878
1879 static int setitimer_helper (const struct itimerval* itnew,
1880                              struct itimerval* itold, struct itimerval* itcurrent,
1881                              MMRESULT* tid, DWORD sigkind)
1882 {
1883   UINT delay, resolution, event_type;
1884
1885   /* First stop the old timer */
1886   if (*tid)
1887     {
1888       timeKillEvent (*tid);
1889       timeEndPeriod (period (itcurrent, timer_prec));
1890       *tid = 0;
1891     }
1892
1893   /* Return old itimerval if requested */
1894   if (itold)
1895     *itold = *itcurrent;
1896
1897   *itcurrent = *itnew;
1898
1899   /* Determine if to start new timer */
1900   delay = period (itnew, 1);
1901   if (delay)
1902     {
1903       resolution = period (itnew, timer_prec);
1904       event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1905         ? TIME_ONESHOT : TIME_PERIODIC;
1906       timeBeginPeriod (resolution);
1907       *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1908     }
1909
1910   return !delay || *tid;
1911 }
1912  
1913 int setitimer (int kind, const struct itimerval* itnew,
1914                struct itimerval* itold)
1915 {
1916   /* In this version, both interval and value are allowed
1917      only if they are equal. */
1918   assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1919           || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
1920           || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
1921               itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
1922
1923   if (kind == ITIMER_REAL)
1924     return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
1925   else if (kind == ITIMER_PROF)
1926     return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
1927   else
1928     return errno = EINVAL;
1929 }
1930
1931 /* end of nt.c */