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