1994-11-01 10:27:02 +00:00
|
|
|
/* Utility and Unix shadow routines for GNU Emacs on Windows NT.
|
1995-04-12 02:10:10 +00:00
|
|
|
Copyright (C) 1994, 1995 Free Software Foundation, Inc.
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1996-01-15 09:18:04 +00:00
|
|
|
This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
GNU Emacs is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with GNU Emacs; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
Boston, MA 02111-1307, USA.
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
|
|
|
|
*/
|
|
|
|
|
1996-01-21 00:31:34 +00:00
|
|
|
|
1994-11-01 10:27:02 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <io.h>
|
1996-05-03 18:32:52 +00:00
|
|
|
#include <errno.h>
|
1994-11-01 10:27:02 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <ctype.h>
|
1996-05-03 18:32:52 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
/* must include CRT headers *before* config.h */
|
|
|
|
#include "config.h"
|
|
|
|
#undef access
|
|
|
|
#undef chdir
|
|
|
|
#undef chmod
|
|
|
|
#undef creat
|
|
|
|
#undef ctime
|
|
|
|
#undef fopen
|
|
|
|
#undef link
|
|
|
|
#undef mkdir
|
|
|
|
#undef mktemp
|
|
|
|
#undef open
|
|
|
|
#undef rename
|
|
|
|
#undef rmdir
|
|
|
|
#undef unlink
|
|
|
|
|
|
|
|
#undef close
|
|
|
|
#undef dup
|
|
|
|
#undef dup2
|
|
|
|
#undef pipe
|
|
|
|
#undef read
|
|
|
|
#undef write
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
#define getwd _getwd
|
|
|
|
#include "lisp.h"
|
|
|
|
#undef getwd
|
|
|
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
#include <windows.h>
|
1996-01-21 00:31:34 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#undef socket
|
|
|
|
#undef bind
|
|
|
|
#undef connect
|
|
|
|
#undef htons
|
|
|
|
#undef ntohs
|
|
|
|
#undef inet_addr
|
|
|
|
#undef gethostname
|
|
|
|
#undef gethostbyname
|
|
|
|
#undef getservbyname
|
|
|
|
#endif
|
1996-01-21 00:31:34 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
#include "nt.h"
|
|
|
|
#include "ndir.h"
|
|
|
|
#include "ntheap.h"
|
1996-01-21 00:31:34 +00:00
|
|
|
|
1994-11-01 10:27:02 +00:00
|
|
|
/* Get the current working directory. */
|
1996-05-03 18:32:52 +00:00
|
|
|
char *
|
1994-11-01 10:27:02 +00:00
|
|
|
getwd (char *dir)
|
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
|
|
|
|
return dir;
|
|
|
|
return NULL;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
#ifndef HAVE_SOCKETS
|
1994-11-01 10:27:02 +00:00
|
|
|
/* Emulate gethostname. */
|
|
|
|
int
|
|
|
|
gethostname (char *buffer, int size)
|
|
|
|
{
|
|
|
|
/* NT only allows small host names, so the buffer is
|
|
|
|
certainly large enough. */
|
|
|
|
return !GetComputerName (buffer, &size);
|
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
#endif /* HAVE_SOCKETS */
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
/* Emulate getloadavg. */
|
|
|
|
int
|
|
|
|
getloadavg (double loadavg[], int nelem)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* A faithful emulation is going to have to be saved for a rainy day. */
|
|
|
|
for (i = 0; i < nelem; i++)
|
|
|
|
{
|
|
|
|
loadavg[i] = 0.0;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emulate the Unix directory procedures opendir, closedir,
|
|
|
|
and readdir. We can't use the procedures supplied in sysdep.c,
|
|
|
|
so we provide them here. */
|
|
|
|
|
|
|
|
struct direct dir_static; /* simulated directory contents */
|
1996-05-03 18:32:52 +00:00
|
|
|
static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
|
|
|
|
static int dir_is_fat;
|
|
|
|
static char dir_pathname[MAXPATHLEN+1];
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
DIR *
|
|
|
|
opendir (char *filename)
|
|
|
|
{
|
|
|
|
DIR *dirp;
|
|
|
|
|
|
|
|
/* Opening is done by FindFirstFile. However, a read is inherent to
|
1996-05-03 18:32:52 +00:00
|
|
|
this operation, so we defer the open until read time. */
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
|
|
|
|
return NULL;
|
|
|
|
if (dir_find_handle != INVALID_HANDLE_VALUE)
|
|
|
|
return NULL;
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
dirp->dd_fd = 0;
|
|
|
|
dirp->dd_loc = 0;
|
|
|
|
dirp->dd_size = 0;
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
strncpy (dir_pathname, filename, MAXPATHLEN);
|
|
|
|
dir_pathname[MAXPATHLEN] = '\0';
|
|
|
|
dir_is_fat = is_fat_volume (filename, NULL);
|
|
|
|
|
1994-11-01 10:27:02 +00:00
|
|
|
return dirp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
closedir (DIR *dirp)
|
|
|
|
{
|
|
|
|
/* If we have a find-handle open, close it. */
|
1996-05-03 18:32:52 +00:00
|
|
|
if (dir_find_handle != INVALID_HANDLE_VALUE)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
|
|
|
FindClose (dir_find_handle);
|
1996-05-03 18:32:52 +00:00
|
|
|
dir_find_handle = INVALID_HANDLE_VALUE;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
xfree ((char *) dirp);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct direct *
|
|
|
|
readdir (DIR *dirp)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATA find_data;
|
|
|
|
|
|
|
|
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
|
1996-05-03 18:32:52 +00:00
|
|
|
if (dir_find_handle == INVALID_HANDLE_VALUE)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
|
|
|
char filename[MAXNAMLEN + 3];
|
|
|
|
int ln;
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
strcpy (filename, dir_pathname);
|
|
|
|
ln = strlen (filename) - 1;
|
|
|
|
if (!IS_DIRECTORY_SEP (filename[ln]))
|
1994-11-01 10:27:02 +00:00
|
|
|
strcat (filename, "\\");
|
1996-05-03 18:32:52 +00:00
|
|
|
strcat (filename, "*");
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
dir_find_handle = FindFirstFile (filename, &find_data);
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
if (dir_find_handle == INVALID_HANDLE_VALUE)
|
1994-11-01 10:27:02 +00:00
|
|
|
return NULL;
|
1996-05-03 18:32:52 +00:00
|
|
|
}
|
|
|
|
else
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
|
|
|
if (!FindNextFile (dir_find_handle, &find_data))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Emacs never uses this value, so don't bother making it match
|
|
|
|
value returned by stat(). */
|
1994-11-01 10:27:02 +00:00
|
|
|
dir_static.d_ino = 1;
|
|
|
|
|
|
|
|
dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
|
|
|
|
dir_static.d_namlen - dir_static.d_namlen % 4;
|
|
|
|
|
|
|
|
dir_static.d_namlen = strlen (find_data.cFileName);
|
1996-05-03 18:32:52 +00:00
|
|
|
strcpy (dir_static.d_name, find_data.cFileName);
|
|
|
|
if (dir_is_fat)
|
|
|
|
_strlwr (dir_static.d_name);
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
return &dir_static;
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Emulate getpwuid, getpwnam and others. */
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1995-06-30 21:12:37 +00:00
|
|
|
#define PASSWD_FIELD_SIZE 256
|
|
|
|
|
|
|
|
static char the_passwd_name[PASSWD_FIELD_SIZE];
|
|
|
|
static char the_passwd_passwd[PASSWD_FIELD_SIZE];
|
|
|
|
static char the_passwd_gecos[PASSWD_FIELD_SIZE];
|
|
|
|
static char the_passwd_dir[PASSWD_FIELD_SIZE];
|
|
|
|
static char the_passwd_shell[PASSWD_FIELD_SIZE];
|
1994-11-01 10:27:02 +00:00
|
|
|
|
|
|
|
static struct passwd the_passwd =
|
|
|
|
{
|
|
|
|
the_passwd_name,
|
|
|
|
the_passwd_passwd,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
the_passwd_gecos,
|
|
|
|
the_passwd_dir,
|
|
|
|
the_passwd_shell,
|
|
|
|
};
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
int
|
|
|
|
getuid ()
|
|
|
|
{
|
|
|
|
return the_passwd.pw_uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
geteuid ()
|
|
|
|
{
|
|
|
|
/* I could imagine arguing for checking to see whether the user is
|
|
|
|
in the Administrators group and returning a UID of 0 for that
|
|
|
|
case, but I don't know how wise that would be in the long run. */
|
|
|
|
return getuid ();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getgid ()
|
|
|
|
{
|
|
|
|
return the_passwd.pw_gid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getegid ()
|
|
|
|
{
|
|
|
|
return getgid ();
|
|
|
|
}
|
|
|
|
|
1994-11-01 10:27:02 +00:00
|
|
|
struct passwd *
|
|
|
|
getpwuid (int uid)
|
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
if (uid == the_passwd.pw_uid)
|
|
|
|
return &the_passwd;
|
|
|
|
return NULL;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct passwd *
|
|
|
|
getpwnam (char *name)
|
|
|
|
{
|
|
|
|
struct passwd *pw;
|
|
|
|
|
|
|
|
pw = getpwuid (getuid ());
|
|
|
|
if (!pw)
|
|
|
|
return pw;
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
if (stricmp (name, pw->pw_name))
|
1994-11-01 10:27:02 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
void
|
|
|
|
init_user_info ()
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Find the user's real name by opening the process token and
|
|
|
|
looking up the name associated with the user-sid in that token.
|
|
|
|
|
|
|
|
Use the relative portion of the identifier authority value from
|
|
|
|
the user-sid as the user id value (same for group id using the
|
|
|
|
primary group sid from the process token). */
|
|
|
|
|
|
|
|
char user_sid[256], name[256], domain[256];
|
|
|
|
DWORD length = sizeof (name), dlength = sizeof (domain), trash;
|
|
|
|
HANDLE token = NULL;
|
|
|
|
SID_NAME_USE user_type;
|
|
|
|
|
|
|
|
if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
|
|
|
|
&& GetTokenInformation (token, TokenUser,
|
|
|
|
(PVOID) user_sid, sizeof (user_sid), &trash)
|
|
|
|
&& LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
|
|
|
|
domain, &dlength, &user_type))
|
1995-10-08 19:38:53 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
strcpy (the_passwd.pw_name, name);
|
|
|
|
/* Determine a reasonable uid value. */
|
|
|
|
if (stricmp ("administrator", name) == 0)
|
|
|
|
{
|
|
|
|
the_passwd.pw_uid = 0;
|
|
|
|
the_passwd.pw_gid = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SID_IDENTIFIER_AUTHORITY * pSIA;
|
|
|
|
|
|
|
|
pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
|
|
|
|
/* I believe the relative portion is the last 4 bytes (of 6)
|
|
|
|
with msb first. */
|
|
|
|
the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
|
|
|
|
(pSIA->Value[3] << 16) +
|
|
|
|
(pSIA->Value[4] << 8) +
|
|
|
|
(pSIA->Value[5] << 0));
|
|
|
|
/* restrict to conventional uid range for normal users */
|
|
|
|
the_passwd.pw_uid = the_passwd.pw_uid % 60001;
|
|
|
|
|
|
|
|
/* Get group id */
|
|
|
|
if (GetTokenInformation (token, TokenPrimaryGroup,
|
|
|
|
(PVOID) user_sid, sizeof (user_sid), &trash))
|
|
|
|
{
|
|
|
|
SID_IDENTIFIER_AUTHORITY * pSIA;
|
|
|
|
|
|
|
|
pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
|
|
|
|
the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
|
|
|
|
(pSIA->Value[3] << 16) +
|
|
|
|
(pSIA->Value[4] << 8) +
|
|
|
|
(pSIA->Value[5] << 0));
|
|
|
|
/* I don't know if this is necessary, but for safety... */
|
|
|
|
the_passwd.pw_gid = the_passwd.pw_gid % 60001;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
the_passwd.pw_gid = the_passwd.pw_uid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If security calls are not supported (presumably because we
|
|
|
|
are running under Windows 95), fallback to this. */
|
|
|
|
else if (GetUserName (name, &length))
|
|
|
|
{
|
|
|
|
strcpy (the_passwd.pw_name, name);
|
|
|
|
if (stricmp ("administrator", name) == 0)
|
|
|
|
the_passwd.pw_uid = 0;
|
|
|
|
else
|
|
|
|
the_passwd.pw_uid = 123;
|
|
|
|
the_passwd.pw_gid = the_passwd.pw_uid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (the_passwd.pw_name, "unknown");
|
|
|
|
the_passwd.pw_uid = 123;
|
|
|
|
the_passwd.pw_gid = 123;
|
1995-10-08 19:38:53 +00:00
|
|
|
}
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Ensure HOME and SHELL are defined. */
|
|
|
|
if (getenv ("HOME") == NULL)
|
|
|
|
putenv ("HOME=c:/");
|
|
|
|
if (getenv ("SHELL") == NULL)
|
|
|
|
putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Set dir and shell from environment variables. */
|
|
|
|
strcpy (the_passwd.pw_dir, getenv ("HOME"));
|
|
|
|
strcpy (the_passwd.pw_shell, getenv ("SHELL"));
|
1995-05-26 05:26:17 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
if (token)
|
|
|
|
CloseHandle (token);
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-05-03 18:32:52 +00:00
|
|
|
random ()
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
/* rand () on NT gives us 15 random bits...hack together 30 bits. */
|
|
|
|
return ((rand () << 15) | rand ());
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1996-05-03 18:32:52 +00:00
|
|
|
srandom (int seed)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
srand (seed);
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Destructively turn backslashes into slashes. */
|
1994-11-01 10:27:02 +00:00
|
|
|
void
|
1996-05-03 18:32:52 +00:00
|
|
|
dostounix_filename (p)
|
|
|
|
register char *p;
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
if (*p == '\\')
|
|
|
|
*p = '/';
|
|
|
|
p++;
|
|
|
|
}
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Destructively turn slashes into backslashes. */
|
1994-11-01 10:27:02 +00:00
|
|
|
void
|
1996-05-03 18:32:52 +00:00
|
|
|
unixtodos_filename (p)
|
|
|
|
register char *p;
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
while (*p)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
if (*p == '/')
|
|
|
|
*p = '\\';
|
|
|
|
p++;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Remove all CR's that are followed by a LF.
|
|
|
|
(From msdos.c...probably should figure out a way to share it,
|
|
|
|
although this code isn't going to ever change.) */
|
1995-04-12 02:10:10 +00:00
|
|
|
int
|
1996-05-03 18:32:52 +00:00
|
|
|
crlf_to_lf (n, buf)
|
|
|
|
register int n;
|
|
|
|
register unsigned char *buf;
|
1995-04-12 02:10:10 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
unsigned char *np = buf;
|
|
|
|
unsigned char *startp = buf;
|
|
|
|
unsigned char *endp = buf + n;
|
1995-04-12 02:10:10 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
if (n == 0)
|
|
|
|
return n;
|
|
|
|
while (buf < endp - 1)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
if (*buf == 0x0d)
|
|
|
|
{
|
|
|
|
if (*(++buf) != 0x0a)
|
|
|
|
*np++ = 0x0d;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*np++ = *buf++;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
if (buf < endp)
|
|
|
|
*np++ = *buf++;
|
|
|
|
return np - startp;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
|
|
|
|
|
|
|
|
int
|
|
|
|
sigsetmask (int signal_mask)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sigblock (int sig)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
setpgrp (int pid, int gid)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
alarm (int seconds)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
unrequest_sigio (void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
request_sigio (void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
|
1995-11-07 07:36:09 +00:00
|
|
|
|
|
|
|
LPBYTE
|
|
|
|
nt_get_resource (key, lpdwtype)
|
|
|
|
char *key;
|
|
|
|
LPDWORD lpdwtype;
|
|
|
|
{
|
|
|
|
LPBYTE lpvalue;
|
|
|
|
HKEY hrootkey = NULL;
|
|
|
|
DWORD cbData;
|
|
|
|
BOOL ok = FALSE;
|
|
|
|
|
|
|
|
/* Check both the current user and the local machine to see if
|
|
|
|
we have any resources. */
|
|
|
|
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
lpvalue = NULL;
|
|
|
|
|
|
|
|
if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
|
|
|
|
&& (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
|
|
|
|
&& RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
return (lpvalue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpvalue) xfree (lpvalue);
|
|
|
|
|
|
|
|
RegCloseKey (hrootkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
lpvalue = NULL;
|
|
|
|
|
|
|
|
if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
|
|
|
|
(lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
|
|
|
|
RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
return (lpvalue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpvalue) xfree (lpvalue);
|
|
|
|
|
|
|
|
RegCloseKey (hrootkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
init_environment ()
|
|
|
|
{
|
|
|
|
/* Check for environment variables and use registry if they don't exist */
|
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
int i;
|
|
|
|
LPBYTE lpval;
|
|
|
|
DWORD dwType;
|
1995-11-07 07:36:09 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
static char * env_vars[] =
|
|
|
|
{
|
|
|
|
"HOME",
|
|
|
|
"emacs_dir",
|
|
|
|
"EMACSLOADPATH",
|
|
|
|
"SHELL",
|
|
|
|
"EMACSDATA",
|
|
|
|
"EMACSPATH",
|
|
|
|
"EMACSLOCKDIR",
|
|
|
|
"INFOPATH",
|
|
|
|
"EMACSDOC",
|
|
|
|
"TERM",
|
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
|
1995-11-07 07:36:09 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
if (!getenv (env_vars[i]) &&
|
|
|
|
(lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
|
|
|
|
{
|
|
|
|
if (dwType == REG_EXPAND_SZ)
|
|
|
|
{
|
|
|
|
char buf1[500], buf2[500];
|
|
|
|
|
|
|
|
ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
|
|
|
|
_snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
|
|
|
|
putenv (strdup (buf2));
|
|
|
|
}
|
|
|
|
else if (dwType == REG_SZ)
|
|
|
|
{
|
|
|
|
char buf[500];
|
1995-11-07 07:36:09 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
_snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
|
|
|
|
putenv (strdup (buf));
|
|
|
|
}
|
1995-11-07 07:36:09 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
xfree (lpval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
init_user_info ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We don't have scripts to automatically determine the system configuration
|
|
|
|
for Emacs before it's compiled, and we don't want to have to make the
|
|
|
|
user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
|
|
|
|
routine. */
|
|
|
|
|
|
|
|
static char configuration_buffer[32];
|
|
|
|
|
|
|
|
char *
|
|
|
|
get_emacs_configuration (void)
|
|
|
|
{
|
|
|
|
char *arch, *oem, *os;
|
|
|
|
|
|
|
|
/* Determine the processor type. */
|
|
|
|
switch (get_processor_type ())
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef PROCESSOR_INTEL_386
|
|
|
|
case PROCESSOR_INTEL_386:
|
|
|
|
case PROCESSOR_INTEL_486:
|
|
|
|
case PROCESSOR_INTEL_PENTIUM:
|
|
|
|
arch = "i386";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PROCESSOR_INTEL_860
|
|
|
|
case PROCESSOR_INTEL_860:
|
|
|
|
arch = "i860";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PROCESSOR_MIPS_R2000
|
|
|
|
case PROCESSOR_MIPS_R2000:
|
|
|
|
case PROCESSOR_MIPS_R3000:
|
|
|
|
case PROCESSOR_MIPS_R4000:
|
|
|
|
arch = "mips";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PROCESSOR_ALPHA_21064
|
|
|
|
case PROCESSOR_ALPHA_21064:
|
|
|
|
arch = "alpha";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
arch = "unknown";
|
|
|
|
break;
|
1995-11-07 07:36:09 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
|
|
|
|
/* Let oem be "*" until we figure out how to decode the OEM field. */
|
|
|
|
oem = "*";
|
|
|
|
|
|
|
|
os = (GetVersion () & 0x80000000) ? "win95" : "nt";
|
|
|
|
|
|
|
|
sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
|
|
|
|
get_nt_major_version (), get_nt_minor_version ());
|
|
|
|
return configuration_buffer;
|
1995-11-07 07:36:09 +00:00
|
|
|
}
|
|
|
|
|
1995-04-12 02:10:10 +00:00
|
|
|
#include <sys/timeb.h>
|
|
|
|
|
|
|
|
/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
|
|
|
|
void
|
|
|
|
gettimeofday (struct timeval *tv, struct timezone *tz)
|
|
|
|
{
|
|
|
|
struct _timeb tb;
|
|
|
|
_ftime (&tb);
|
|
|
|
|
|
|
|
tv->tv_sec = tb.time;
|
|
|
|
tv->tv_usec = tb.millitm * 1000L;
|
|
|
|
if (tz)
|
|
|
|
{
|
|
|
|
tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
|
|
|
|
tz->tz_dsttime = tb.dstflag; /* type of dst correction */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* IO support and wrapper functions for Win32 API. */
|
|
|
|
/* ------------------------------------------------------------------------- */
|
1994-11-01 10:27:02 +00:00
|
|
|
|
1996-05-03 18:32:52 +00:00
|
|
|
/* Place a wrapper around the MSVC version of ctime. It returns NULL
|
|
|
|
on network directories, so we handle that case here.
|
|
|
|
(Ulrich Leodolter, 1/11/95). */
|
|
|
|
char *
|
|
|
|
sys_ctime (const time_t *t)
|
|
|
|
{
|
|
|
|
char *str = (char *) ctime (t);
|
|
|
|
return (str ? str : "Sun Jan 01 00:00:00 1970");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emulate sleep...we could have done this with a define, but that
|
|
|
|
would necessitate including windows.h in the files that used it.
|
|
|
|
This is much easier. */
|
|
|
|
void
|
|
|
|
sys_sleep (int seconds)
|
|
|
|
{
|
|
|
|
Sleep (seconds * 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Internal MSVC data and functions for low-level descriptor munging */
|
|
|
|
#if (_MSC_VER == 900)
|
|
|
|
extern char _osfile[];
|
|
|
|
#endif
|
|
|
|
extern int __cdecl _set_osfhnd (int fd, long h);
|
|
|
|
extern int __cdecl _free_osfhnd (int fd);
|
|
|
|
|
|
|
|
/* parallel array of private info on file handles */
|
|
|
|
filedesc fd_info [ MAXDESC ];
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
DWORD serialnum;
|
|
|
|
DWORD maxcomp;
|
|
|
|
DWORD flags;
|
|
|
|
char name[32];
|
|
|
|
char type[32];
|
|
|
|
} volume_info;
|
|
|
|
|
|
|
|
/* Get information on the volume where name is held; set path pointer to
|
|
|
|
start of pathname in name (past UNC header\volume header if present). */
|
|
|
|
int
|
|
|
|
get_volume_info (const char * name, const char ** pPath)
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
char temp[MAX_PATH];
|
|
|
|
char *rootname = NULL; /* default to current volume */
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* find the root name of the volume if given */
|
|
|
|
if (isalpha (name[0]) && name[1] == ':')
|
|
|
|
{
|
|
|
|
rootname = temp;
|
|
|
|
temp[0] = *name++;
|
|
|
|
temp[1] = *name++;
|
|
|
|
temp[2] = '\\';
|
|
|
|
temp[3] = 0;
|
|
|
|
}
|
|
|
|
else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
char *str = temp;
|
|
|
|
int slashes = 4;
|
|
|
|
rootname = temp;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
|
|
|
|
break;
|
|
|
|
*str++ = *name++;
|
|
|
|
}
|
|
|
|
while ( *name );
|
|
|
|
|
|
|
|
if (slashes > 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*str++ = '\\';
|
|
|
|
*str = 0;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
|
|
|
|
if (pPath)
|
|
|
|
*pPath = name;
|
|
|
|
|
|
|
|
if (GetVolumeInformation (rootname,
|
|
|
|
volume_info.name, 32,
|
|
|
|
&volume_info.serialnum,
|
|
|
|
&volume_info.maxcomp,
|
|
|
|
&volume_info.flags,
|
|
|
|
volume_info.type, 32))
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
return TRUE;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine if volume is FAT format (ie. only supports short 8.3
|
|
|
|
names); also set path pointer to start of pathname in name. */
|
|
|
|
int
|
|
|
|
is_fat_volume (const char * name, const char ** pPath)
|
|
|
|
{
|
|
|
|
if (get_volume_info (name, pPath))
|
|
|
|
return (volume_info.maxcomp == 12);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Map filename to a legal 8.3 name if necessary. */
|
|
|
|
const char *
|
|
|
|
map_win32_filename (const char * name, const char ** pPath)
|
|
|
|
{
|
|
|
|
static char shortname[MAX_PATH];
|
|
|
|
char * str = shortname;
|
|
|
|
char c;
|
|
|
|
const char * orig_name = name;
|
|
|
|
char * path;
|
|
|
|
|
|
|
|
if (is_fat_volume (name, &path)) /* truncate to 8.3 */
|
1994-11-01 10:27:02 +00:00
|
|
|
{
|
1996-05-03 18:32:52 +00:00
|
|
|
register int left = 8; /* maximum number of chars in part */
|
|
|
|
register int extn = 0; /* extension added? */
|
|
|
|
register int dots = 2; /* maximum number of dots allowed */
|
|
|
|
|
|
|
|
while (name < path)
|
|
|
|
*str++ = *name++; /* skip past UNC header */
|
|
|
|
|
|
|
|
while ((c = *name++))
|
|
|
|
{
|
|
|
|
switch ( c )
|
|
|
|
{
|
|
|
|
case '\\':
|
|
|
|
case '/':
|
|
|
|
*str++ = '\\';
|
|
|
|
extn = 0; /* reset extension flags */
|
|
|
|
dots = 2; /* max 2 dots */
|
|
|
|
left = 8; /* max length 8 for main part */
|
|
|
|
break;
|
|
|
|
case ':':
|
|
|
|
*str++ = ':';
|
|
|
|
extn = 0; /* reset extension flags */
|
|
|
|
dots = 2; /* max 2 dots */
|
|
|
|
left = 8; /* max length 8 for main part */
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
if ( dots )
|
|
|
|
{
|
|
|
|
/* Convert path components of the form .xxx to _xxx,
|
|
|
|
but leave . and .. as they are. This allows .emacs
|
|
|
|
to be read as _emacs, for example. */
|
|
|
|
|
|
|
|
if (! *name ||
|
|
|
|
*name == '.' ||
|
|
|
|
IS_DIRECTORY_SEP (*name))
|
|
|
|
{
|
|
|
|
*str++ = '.';
|
|
|
|
dots--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*str++ = '_';
|
|
|
|
left--;
|
|
|
|
dots = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( !extn )
|
|
|
|
{
|
|
|
|
*str++ = '.';
|
|
|
|
extn = 1; /* we've got an extension */
|
|
|
|
left = 3; /* 3 chars in extension */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* any embedded dots after the first are converted to _ */
|
|
|
|
*str++ = '_';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
case '#': /* don't lose these, they're important */
|
|
|
|
if ( ! left )
|
|
|
|
str[-1] = c; /* replace last character of part */
|
|
|
|
/* FALLTHRU */
|
|
|
|
default:
|
|
|
|
if ( left )
|
|
|
|
{
|
|
|
|
*str++ = tolower (c); /* map to lower case (looks nicer) */
|
|
|
|
left--;
|
|
|
|
dots = 0; /* started a path component */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*str = '\0';
|
|
|
|
|
|
|
|
name = shortname;
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
|
|
|
|
if (pPath)
|
|
|
|
*pPath = name + (path - orig_name);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Shadow some MSVC runtime functions to map requests for long filenames
|
|
|
|
to reasonable short names if necessary. This was originally added to
|
|
|
|
permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
|
|
|
|
long file names. */
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_access (const char * path, int mode)
|
|
|
|
{
|
|
|
|
return _access (map_win32_filename (path, NULL), mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_chdir (const char * path)
|
|
|
|
{
|
|
|
|
return _chdir (map_win32_filename (path, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_chmod (const char * path, int mode)
|
|
|
|
{
|
|
|
|
return _chmod (map_win32_filename (path, NULL), mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_creat (const char * path, int mode)
|
|
|
|
{
|
|
|
|
return _creat (map_win32_filename (path, NULL), mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
sys_fopen(const char * path, const char * mode)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int oflag;
|
|
|
|
const char * mode_save = mode;
|
|
|
|
|
|
|
|
/* Force all file handles to be non-inheritable. This is necessary to
|
|
|
|
ensure child processes don't unwittingly inherit handles that might
|
|
|
|
prevent future file access. */
|
|
|
|
|
|
|
|
if (mode[0] == 'r')
|
|
|
|
oflag = O_RDONLY;
|
|
|
|
else if (mode[0] == 'w' || mode[0] == 'a')
|
|
|
|
oflag = O_WRONLY | O_CREAT | O_TRUNC;
|
1994-11-01 10:27:02 +00:00
|
|
|
else
|
1996-05-03 18:32:52 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Only do simplistic option parsing. */
|
|
|
|
while (*++mode)
|
|
|
|
if (mode[0] == '+')
|
|
|
|
{
|
|
|
|
oflag &= ~(O_RDONLY | O_WRONLY);
|
|
|
|
oflag |= O_RDWR;
|
|
|
|
}
|
|
|
|
else if (mode[0] == 'b')
|
|
|
|
{
|
|
|
|
oflag &= ~O_TEXT;
|
|
|
|
oflag |= O_BINARY;
|
|
|
|
}
|
|
|
|
else if (mode[0] == 't')
|
|
|
|
{
|
|
|
|
oflag &= ~O_BINARY;
|
|
|
|
oflag |= O_TEXT;
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
|
|
|
|
fd = _open (map_win32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return fdopen (fd, mode_save);
|
1994-11-01 10:27:02 +00:00
|
|
|
}
|
1996-05-03 18:32:52 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
sys_link (const char * path1, const char * path2)
|
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_mkdir (const char * path)
|
|
|
|
{
|
|
|
|
return _mkdir (map_win32_filename (path, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
sys_mktemp (char * template)
|
|
|
|
{
|
|
|
|
return (char *) map_win32_filename ((const char *) _mktemp (template), NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_open (const char * path, int oflag, int mode)
|
|
|
|
{
|
|
|
|
/* Force all file handles to be non-inheritable. */
|
|
|
|
return _open (map_win32_filename (path, NULL), oflag | _O_NOINHERIT, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_rename (const char * oldname, const char * newname)
|
|
|
|
{
|
|
|
|
char temp[MAX_PATH];
|
|
|
|
|
|
|
|
/* MoveFile on Win95 doesn't correctly change the short file name
|
|
|
|
alias when oldname has a three char extension and newname has the
|
|
|
|
same first three chars in its extension. To avoid problems, on
|
|
|
|
Win95 we rename to a temporary name first. */
|
|
|
|
|
|
|
|
strcpy (temp, map_win32_filename (oldname, NULL));
|
|
|
|
|
|
|
|
if (GetVersion () & 0x80000000)
|
|
|
|
{
|
|
|
|
char * p;
|
|
|
|
|
|
|
|
unixtodos_filename (temp);
|
|
|
|
if (p = strrchr (temp, '\\'))
|
|
|
|
p++;
|
|
|
|
else
|
|
|
|
p = temp;
|
|
|
|
strcpy (p, "__XXXXXX");
|
|
|
|
_mktemp (temp);
|
|
|
|
if (rename (map_win32_filename (oldname, NULL), temp) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emulate Unix behaviour - newname is deleted if it already exists
|
|
|
|
(at least if it is a file; don't do this for directories). */
|
|
|
|
newname = map_win32_filename (newname, NULL);
|
|
|
|
if (GetFileAttributes (newname) != -1)
|
|
|
|
{
|
|
|
|
_chmod (newname, 0666);
|
|
|
|
_unlink (newname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rename (temp, newname);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_rmdir (const char * path)
|
|
|
|
{
|
|
|
|
return _rmdir (map_win32_filename (path, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_unlink (const char * path)
|
|
|
|
{
|
|
|
|
return _unlink (map_win32_filename (path, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
static FILETIME utc_base_ft;
|
|
|
|
static long double utc_base;
|
|
|
|
static int init = 0;
|
|
|
|
|
|
|
|
static time_t
|
|
|
|
convert_time (FILETIME ft)
|
|
|
|
{
|
|
|
|
long double ret;
|
|
|
|
|
|
|
|
if (!init)
|
|
|
|
{
|
|
|
|
/* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
|
|
|
|
SYSTEMTIME st;
|
|
|
|
|
|
|
|
st.wYear = 1970;
|
|
|
|
st.wMonth = 1;
|
|
|
|
st.wDay = 1;
|
|
|
|
st.wHour = 0;
|
|
|
|
st.wMinute = 0;
|
|
|
|
st.wSecond = 0;
|
|
|
|
st.wMilliseconds = 0;
|
|
|
|
|
|
|
|
SystemTimeToFileTime (&st, &utc_base_ft);
|
|
|
|
utc_base = (long double) utc_base_ft.dwHighDateTime
|
|
|
|
* 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
|
|
|
|
init = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CompareFileTime (&ft, &utc_base_ft) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
|
|
|
|
ret -= utc_base;
|
|
|
|
return (time_t) (ret * 1e-7);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* in case we ever have need of this */
|
|
|
|
void
|
|
|
|
convert_from_time_t (time_t time, FILETIME * pft)
|
|
|
|
{
|
|
|
|
long double tmp;
|
|
|
|
|
|
|
|
if (!init)
|
|
|
|
{
|
|
|
|
/* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
|
|
|
|
SYSTEMTIME st;
|
|
|
|
|
|
|
|
st.wYear = 1970;
|
|
|
|
st.wMonth = 1;
|
|
|
|
st.wDay = 1;
|
|
|
|
st.wHour = 0;
|
|
|
|
st.wMinute = 0;
|
|
|
|
st.wSecond = 0;
|
|
|
|
st.wMilliseconds = 0;
|
|
|
|
|
|
|
|
SystemTimeToFileTime (&st, &utc_base_ft);
|
|
|
|
utc_base = (long double) utc_base_ft.dwHighDateTime
|
|
|
|
* 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
|
|
|
|
init = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* time in 100ns units since 1-Jan-1601 */
|
|
|
|
tmp = (long double) time * 1e7 + utc_base;
|
|
|
|
pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
|
|
|
|
pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* "PJW" algorithm (see the "Dragon" compiler book). */
|
|
|
|
static unsigned
|
|
|
|
hashval (const char * str)
|
|
|
|
{
|
|
|
|
unsigned h = 0;
|
|
|
|
unsigned g;
|
|
|
|
while (*str)
|
|
|
|
{
|
|
|
|
h = (h << 4) + *str++;
|
|
|
|
if ((g = h & 0xf0000000) != 0)
|
|
|
|
h = (h ^ (g >> 24)) & 0x0fffffff;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the hash value of the canonical pathname, excluding the
|
|
|
|
drive/UNC header, to get a hopefully unique inode number. */
|
|
|
|
static _ino_t
|
|
|
|
generate_inode_val (const char * name)
|
|
|
|
{
|
|
|
|
char fullname[ MAX_PATH ];
|
|
|
|
char * p;
|
|
|
|
unsigned hash;
|
|
|
|
|
|
|
|
GetFullPathName (name, sizeof (fullname), fullname, &p);
|
|
|
|
get_volume_info (fullname, &p);
|
|
|
|
/* Normal Win32 filesystems are still case insensitive. */
|
|
|
|
_strlwr (p);
|
|
|
|
hash = hashval (p);
|
|
|
|
return (_ino_t) (hash ^ (hash >> 16));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MSVC stat function can't cope with UNC names and has other bugs, so
|
|
|
|
replace it with our own. This also allows us to calculate consistent
|
|
|
|
inode values without hacks in the main Emacs code. */
|
|
|
|
int
|
|
|
|
stat (const char * path, struct stat * buf)
|
|
|
|
{
|
|
|
|
char * name;
|
|
|
|
WIN32_FIND_DATA wfd;
|
|
|
|
HANDLE fh;
|
|
|
|
int permission;
|
|
|
|
int len;
|
|
|
|
int rootdir = FALSE;
|
|
|
|
|
|
|
|
if (path == NULL || buf == NULL)
|
|
|
|
{
|
|
|
|
errno = EFAULT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = (char *) map_win32_filename (path, &path);
|
|
|
|
/* must be valid filename, no wild cards */
|
|
|
|
if (strchr (name, '*') || strchr (name, '?'))
|
|
|
|
{
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove trailing directory separator, unless name is the root
|
|
|
|
directory of a drive or UNC volume in which case ensure there
|
|
|
|
is a trailing separator. */
|
|
|
|
len = strlen (name);
|
|
|
|
rootdir = (path >= name + len - 1
|
|
|
|
&& (IS_DIRECTORY_SEP (*path) || *path == 0));
|
|
|
|
name = strcpy (alloca (len + 2), name);
|
|
|
|
|
|
|
|
if (rootdir)
|
|
|
|
{
|
|
|
|
if (!IS_DIRECTORY_SEP (name[len-1]))
|
|
|
|
strcat (name, "\\");
|
|
|
|
if (GetDriveType (name) < 2)
|
|
|
|
{
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memset (&wfd, 0, sizeof (wfd));
|
|
|
|
wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
wfd.ftCreationTime = utc_base_ft;
|
|
|
|
wfd.ftLastAccessTime = utc_base_ft;
|
|
|
|
wfd.ftLastWriteTime = utc_base_ft;
|
|
|
|
strcpy (wfd.cFileName, name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (IS_DIRECTORY_SEP (name[len-1]))
|
|
|
|
name[len - 1] = 0;
|
|
|
|
fh = FindFirstFile (name, &wfd);
|
|
|
|
if (fh == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
FindClose (fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
{
|
|
|
|
buf->st_mode = _S_IFDIR;
|
|
|
|
buf->st_nlink = 2; /* doesn't really matter */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
/* This is more accurate in terms of gettting the correct number
|
|
|
|
of links, but is quite slow (it is noticable when Emacs is
|
|
|
|
making a list of file name completions). */
|
|
|
|
BY_HANDLE_FILE_INFORMATION info;
|
|
|
|
|
|
|
|
fh = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
|
|
if (GetFileInformationByHandle (fh, &info))
|
|
|
|
{
|
|
|
|
switch (GetFileType (fh))
|
|
|
|
{
|
|
|
|
case FILE_TYPE_DISK:
|
|
|
|
buf->st_mode = _S_IFREG;
|
|
|
|
break;
|
|
|
|
case FILE_TYPE_PIPE:
|
|
|
|
buf->st_mode = _S_IFIFO;
|
|
|
|
break;
|
|
|
|
case FILE_TYPE_CHAR:
|
|
|
|
case FILE_TYPE_UNKNOWN:
|
|
|
|
default:
|
|
|
|
buf->st_mode = _S_IFCHR;
|
|
|
|
}
|
|
|
|
buf->st_nlink = info.nNumberOfLinks;
|
|
|
|
/* Could use file index, but this is not guaranteed to be
|
|
|
|
unique unless we keep a handle open all the time. */
|
|
|
|
/* buf->st_ino = info.nFileIndexLow ^ info.nFileIndexHigh; */
|
|
|
|
CloseHandle (fh);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
errno = EACCES;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
buf->st_mode = _S_IFREG;
|
|
|
|
buf->st_nlink = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* consider files to belong to current user */
|
|
|
|
buf->st_uid = the_passwd.pw_uid;
|
|
|
|
buf->st_gid = the_passwd.pw_gid;
|
|
|
|
|
|
|
|
/* volume_info is set indirectly by map_win32_filename */
|
|
|
|
buf->st_dev = volume_info.serialnum;
|
|
|
|
buf->st_rdev = volume_info.serialnum;
|
|
|
|
|
|
|
|
buf->st_ino = generate_inode_val (name);
|
|
|
|
|
|
|
|
buf->st_size = wfd.nFileSizeLow;
|
|
|
|
|
|
|
|
/* Convert timestamps to Unix format. */
|
|
|
|
buf->st_mtime = convert_time (wfd.ftLastWriteTime);
|
|
|
|
buf->st_atime = convert_time (wfd.ftLastAccessTime);
|
|
|
|
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
|
|
|
|
buf->st_ctime = convert_time (wfd.ftCreationTime);
|
|
|
|
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
|
|
|
|
|
|
|
|
/* determine rwx permissions */
|
|
|
|
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
|
|
|
|
permission = _S_IREAD;
|
|
|
|
else
|
|
|
|
permission = _S_IREAD | _S_IWRITE;
|
|
|
|
|
|
|
|
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
permission |= _S_IEXEC;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char * p = strrchr (name, '.');
|
|
|
|
if (p != NULL &&
|
|
|
|
(stricmp (p, ".exe") == 0 ||
|
|
|
|
stricmp (p, ".com") == 0 ||
|
|
|
|
stricmp (p, ".bat") == 0 ||
|
|
|
|
stricmp (p, ".cmd") == 0))
|
|
|
|
permission |= _S_IEXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
|
|
|
|
/* Wrappers for winsock functions to map between our file descriptors
|
|
|
|
and winsock's handles; also set h_errno for convenience.
|
|
|
|
|
|
|
|
To allow Emacs to run on systems which don't have winsock support
|
|
|
|
installed, we dynamically link to winsock on startup if present, and
|
|
|
|
otherwise provide the minimum necessary functionality
|
|
|
|
(eg. gethostname). */
|
|
|
|
|
|
|
|
/* function pointers for relevant socket functions */
|
|
|
|
int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
|
|
|
|
void (PASCAL *pfn_WSASetLastError) (int iError);
|
|
|
|
int (PASCAL *pfn_WSAGetLastError) (void);
|
|
|
|
int (PASCAL *pfn_socket) (int af, int type, int protocol);
|
|
|
|
int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
|
|
|
|
int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
|
|
|
|
int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
|
|
|
|
int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
|
|
|
|
int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
|
|
|
|
int (PASCAL *pfn_closesocket) (SOCKET s);
|
|
|
|
int (PASCAL *pfn_shutdown) (SOCKET s, int how);
|
|
|
|
int (PASCAL *pfn_WSACleanup) (void);
|
|
|
|
|
|
|
|
u_short (PASCAL *pfn_htons) (u_short hostshort);
|
|
|
|
u_short (PASCAL *pfn_ntohs) (u_short netshort);
|
|
|
|
unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
|
|
|
|
int (PASCAL *pfn_gethostname) (char * name, int namelen);
|
|
|
|
struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
|
|
|
|
struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
|
|
|
|
|
|
|
|
static int have_winsock;
|
|
|
|
static HANDLE winsock_lib;
|
|
|
|
|
|
|
|
static void
|
|
|
|
term_winsock (void)
|
|
|
|
{
|
|
|
|
if (have_winsock)
|
|
|
|
{
|
|
|
|
pfn_WSACleanup ();
|
|
|
|
FreeLibrary (winsock_lib);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_winsock ()
|
|
|
|
{
|
|
|
|
WSADATA winsockData;
|
|
|
|
|
|
|
|
winsock_lib = LoadLibrary ("wsock32.dll");
|
|
|
|
|
|
|
|
if (winsock_lib != NULL)
|
|
|
|
{
|
|
|
|
/* dynamically link to socket functions */
|
|
|
|
|
|
|
|
#define LOAD_PROC(fn) \
|
|
|
|
if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
LOAD_PROC( WSAStartup );
|
|
|
|
LOAD_PROC( WSASetLastError );
|
|
|
|
LOAD_PROC( WSAGetLastError );
|
|
|
|
LOAD_PROC( socket );
|
|
|
|
LOAD_PROC( bind );
|
|
|
|
LOAD_PROC( connect );
|
|
|
|
LOAD_PROC( ioctlsocket );
|
|
|
|
LOAD_PROC( recv );
|
|
|
|
LOAD_PROC( send );
|
|
|
|
LOAD_PROC( closesocket );
|
|
|
|
LOAD_PROC( shutdown );
|
|
|
|
LOAD_PROC( htons );
|
|
|
|
LOAD_PROC( ntohs );
|
|
|
|
LOAD_PROC( inet_addr );
|
|
|
|
LOAD_PROC( gethostname );
|
|
|
|
LOAD_PROC( gethostbyname );
|
|
|
|
LOAD_PROC( getservbyname );
|
|
|
|
LOAD_PROC( WSACleanup );
|
|
|
|
|
|
|
|
/* specify version 1.1 of winsock */
|
|
|
|
if (pfn_WSAStartup (0x101, &winsockData) == 0)
|
|
|
|
{
|
|
|
|
have_winsock = TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
FreeLibrary (winsock_lib);
|
|
|
|
}
|
|
|
|
have_winsock = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int h_errno = 0;
|
|
|
|
|
|
|
|
/* function to set h_errno for compatability; map winsock error codes to
|
|
|
|
normal system codes where they overlap (non-overlapping definitions
|
|
|
|
are already in <sys/socket.h> */
|
|
|
|
static void set_errno ()
|
|
|
|
{
|
|
|
|
if (!have_winsock)
|
|
|
|
h_errno = EINVAL;
|
|
|
|
else
|
|
|
|
h_errno = pfn_WSAGetLastError ();
|
|
|
|
|
|
|
|
switch (h_errno)
|
|
|
|
{
|
|
|
|
case WSAEACCES: h_errno = EACCES; break;
|
|
|
|
case WSAEBADF: h_errno = EBADF; break;
|
|
|
|
case WSAEFAULT: h_errno = EFAULT; break;
|
|
|
|
case WSAEINTR: h_errno = EINTR; break;
|
|
|
|
case WSAEINVAL: h_errno = EINVAL; break;
|
|
|
|
case WSAEMFILE: h_errno = EMFILE; break;
|
|
|
|
case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
|
|
|
|
case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
|
|
|
|
}
|
|
|
|
errno = h_errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_errno ()
|
|
|
|
{
|
|
|
|
if (h_errno == 0 && have_winsock)
|
|
|
|
pfn_WSASetLastError (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* [andrewi 3-May-96] I've had conflicting results using both methods,
|
|
|
|
but I believe the method of keeping the socket handle separate (and
|
|
|
|
insuring it is not inheritable) is the correct one. */
|
|
|
|
|
|
|
|
//#define SOCK_REPLACE_HANDLE
|
|
|
|
|
|
|
|
#ifdef SOCK_REPLACE_HANDLE
|
|
|
|
#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
|
|
|
|
#else
|
|
|
|
#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_socket(int af, int type, int protocol)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
long s;
|
|
|
|
child_process * cp;
|
|
|
|
|
|
|
|
if (!have_winsock)
|
|
|
|
{
|
|
|
|
h_errno = ENETDOWN;
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_errno ();
|
|
|
|
|
|
|
|
/* call the real socket function */
|
|
|
|
s = (long) pfn_socket (af, type, protocol);
|
|
|
|
|
|
|
|
if (s != INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
/* Although under NT 3.5 _open_osfhandle will accept a socket
|
|
|
|
handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
|
|
|
|
that does not work under NT 3.1. However, we can get the same
|
|
|
|
effect by using a backdoor function to replace an existing
|
|
|
|
descriptor handle with the one we want. */
|
|
|
|
|
|
|
|
/* allocate a file descriptor (with appropriate flags) */
|
|
|
|
fd = _open ("NUL:", _O_RDWR);
|
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
#ifdef SOCK_REPLACE_HANDLE
|
|
|
|
/* now replace handle to NUL with our socket handle */
|
|
|
|
CloseHandle ((HANDLE) _get_osfhandle (fd));
|
|
|
|
_free_osfhnd (fd);
|
|
|
|
_set_osfhnd (fd, s);
|
|
|
|
/* setmode (fd, _O_BINARY); */
|
|
|
|
#else
|
|
|
|
/* Make a non-inheritable copy of the socket handle. */
|
|
|
|
{
|
|
|
|
HANDLE parent;
|
|
|
|
HANDLE new_s = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
parent = GetCurrentProcess ();
|
|
|
|
|
|
|
|
DuplicateHandle (parent,
|
|
|
|
(HANDLE) s,
|
|
|
|
parent,
|
|
|
|
&new_s,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
pfn_closesocket (s);
|
|
|
|
fd_info[fd].hnd = new_s;
|
|
|
|
s = (SOCKET) new_s;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* set our own internal flags */
|
|
|
|
fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
|
|
|
|
|
|
|
|
cp = new_child ();
|
|
|
|
if (cp)
|
|
|
|
{
|
|
|
|
cp->fd = fd;
|
|
|
|
cp->status = STATUS_READ_ACKNOWLEDGED;
|
|
|
|
|
|
|
|
/* attach child_process to fd_info */
|
|
|
|
if (fd_info[ fd ].cp != NULL)
|
|
|
|
{
|
|
|
|
DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
|
|
|
|
fd_info[ fd ].cp = cp;
|
|
|
|
|
|
|
|
/* success! */
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up */
|
|
|
|
_close (fd);
|
|
|
|
}
|
|
|
|
pfn_closesocket (s);
|
|
|
|
h_errno = EMFILE;
|
|
|
|
}
|
|
|
|
set_errno ();
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_bind (int s, const struct sockaddr * addr, int namelen)
|
|
|
|
{
|
|
|
|
if (!have_winsock)
|
|
|
|
{
|
|
|
|
h_errno = ENOTSOCK;
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_errno ();
|
|
|
|
if (fd_info[s].flags & FILE_SOCKET)
|
|
|
|
{
|
|
|
|
int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
|
|
|
|
if (rc == SOCKET_ERROR)
|
|
|
|
set_errno ();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
h_errno = ENOTSOCK;
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_connect (int s, const struct sockaddr * name, int namelen)
|
|
|
|
{
|
|
|
|
if (!have_winsock)
|
|
|
|
{
|
|
|
|
h_errno = ENOTSOCK;
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_errno ();
|
|
|
|
if (fd_info[s].flags & FILE_SOCKET)
|
|
|
|
{
|
|
|
|
int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
|
|
|
|
if (rc == SOCKET_ERROR)
|
|
|
|
set_errno ();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
h_errno = ENOTSOCK;
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_short
|
|
|
|
sys_htons (u_short hostshort)
|
|
|
|
{
|
|
|
|
return (have_winsock) ?
|
|
|
|
pfn_htons (hostshort) : hostshort;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_short
|
|
|
|
sys_ntohs (u_short netshort)
|
|
|
|
{
|
|
|
|
return (have_winsock) ?
|
|
|
|
pfn_ntohs (netshort) : netshort;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long
|
|
|
|
sys_inet_addr (const char * cp)
|
|
|
|
{
|
|
|
|
return (have_winsock) ?
|
|
|
|
pfn_inet_addr (cp) : INADDR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_gethostname (char * name, int namelen)
|
|
|
|
{
|
|
|
|
if (have_winsock)
|
|
|
|
return pfn_gethostname (name, namelen);
|
|
|
|
|
|
|
|
if (namelen > MAX_COMPUTERNAME_LENGTH)
|
|
|
|
return !GetComputerName (name, &namelen);
|
|
|
|
|
|
|
|
h_errno = EFAULT;
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct hostent *
|
|
|
|
sys_gethostbyname(const char * name)
|
|
|
|
{
|
|
|
|
struct hostent * host;
|
|
|
|
|
|
|
|
if (!have_winsock)
|
|
|
|
{
|
|
|
|
h_errno = ENETDOWN;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_errno ();
|
|
|
|
host = pfn_gethostbyname (name);
|
|
|
|
if (!host)
|
|
|
|
set_errno ();
|
|
|
|
return host;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct servent *
|
|
|
|
sys_getservbyname(const char * name, const char * proto)
|
|
|
|
{
|
|
|
|
struct servent * serv;
|
|
|
|
|
|
|
|
if (!have_winsock)
|
|
|
|
{
|
|
|
|
h_errno = ENETDOWN;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_errno ();
|
|
|
|
serv = pfn_getservbyname (name, proto);
|
|
|
|
if (!serv)
|
|
|
|
set_errno ();
|
|
|
|
return serv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_SOCKETS */
|
|
|
|
|
|
|
|
|
|
|
|
/* Shadow main io functions: we need to handle pipes and sockets more
|
|
|
|
intelligently, and implement non-blocking mode as well. */
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_close (int fd)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (fd < 0 || fd >= MAXDESC)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd_info[fd].cp)
|
|
|
|
{
|
|
|
|
child_process * cp = fd_info[fd].cp;
|
|
|
|
|
|
|
|
fd_info[fd].cp = NULL;
|
|
|
|
|
|
|
|
if (CHILD_ACTIVE (cp))
|
|
|
|
{
|
|
|
|
/* if last descriptor to active child_process then cleanup */
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAXDESC; i++)
|
|
|
|
{
|
|
|
|
if (i == fd)
|
|
|
|
continue;
|
|
|
|
if (fd_info[i].cp == cp)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == MAXDESC)
|
|
|
|
{
|
|
|
|
#if defined (HAVE_SOCKETS) && !defined (SOCK_REPLACE_HANDLE)
|
|
|
|
if (fd_info[fd].flags & FILE_SOCKET)
|
|
|
|
{
|
|
|
|
if (!have_winsock) abort ();
|
|
|
|
|
|
|
|
pfn_shutdown (SOCK_HANDLE (fd), 2);
|
|
|
|
rc = pfn_closesocket (SOCK_HANDLE (fd));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
delete_child (cp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note that sockets do not need special treatment here (at least on
|
|
|
|
NT and Win95 using the standard tcp/ip stacks) - it appears that
|
|
|
|
closesocket is equivalent to CloseHandle, which is to be expected
|
|
|
|
because socket handles are fully fledged kernel handles. */
|
|
|
|
rc = _close (fd);
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
fd_info[fd].flags = 0;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_dup (int fd)
|
|
|
|
{
|
|
|
|
int new_fd;
|
|
|
|
|
|
|
|
new_fd = _dup (fd);
|
|
|
|
if (new_fd >= 0)
|
|
|
|
{
|
|
|
|
/* duplicate our internal info as well */
|
|
|
|
fd_info[new_fd] = fd_info[fd];
|
|
|
|
}
|
|
|
|
return new_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_dup2 (int src, int dst)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (dst < 0 || dst >= MAXDESC)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure we close the destination first if it's a pipe or socket */
|
|
|
|
if (src != dst && fd_info[dst].flags != 0)
|
|
|
|
sys_close (dst);
|
|
|
|
|
|
|
|
rc = _dup2 (src, dst);
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
/* duplicate our internal info as well */
|
|
|
|
fd_info[dst] = fd_info[src];
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From callproc.c */
|
|
|
|
extern Lisp_Object Vbinary_process_input;
|
|
|
|
extern Lisp_Object Vbinary_process_output;
|
|
|
|
|
|
|
|
/* Unix pipe() has only one arg */
|
|
|
|
int
|
|
|
|
sys_pipe (int * phandles)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned flags;
|
|
|
|
child_process * cp;
|
|
|
|
|
|
|
|
/* make pipe handles non-inheritable; when we spawn a child,
|
|
|
|
we replace the relevant handle with an inheritable one. */
|
|
|
|
rc = _pipe (phandles, 0, _O_NOINHERIT);
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
{
|
|
|
|
/* set internal flags, and put read and write handles into binary
|
|
|
|
mode as necessary; if not in binary mode, set the MSVC internal
|
|
|
|
FDEV (0x40) flag to prevent _read from treating ^Z as eof (this
|
|
|
|
could otherwise allow Emacs to hang because it then waits
|
|
|
|
indefinitely for the child process to exit, when it might not be
|
|
|
|
finished). */
|
|
|
|
flags = FILE_PIPE | FILE_READ;
|
|
|
|
if (!NILP (Vbinary_process_output))
|
|
|
|
{
|
|
|
|
flags |= FILE_BINARY;
|
|
|
|
setmode (phandles[0], _O_BINARY);
|
|
|
|
}
|
|
|
|
#if (_MSC_VER == 900)
|
|
|
|
else
|
|
|
|
_osfile[phandles[0]] |= 0x40;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fd_info[phandles[0]].flags = flags;
|
|
|
|
|
|
|
|
flags = FILE_PIPE | FILE_WRITE;
|
|
|
|
if (!NILP (Vbinary_process_input))
|
|
|
|
{
|
|
|
|
flags |= FILE_BINARY;
|
|
|
|
setmode (phandles[1], _O_BINARY);
|
|
|
|
}
|
|
|
|
#if (_MSC_VER == 900)
|
|
|
|
else
|
|
|
|
_osfile[phandles[1]] |= 0x40;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fd_info[phandles[1]].flags = flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function to do blocking read of one byte, needed to implement
|
|
|
|
select. It is only allowed on sockets and pipes. */
|
|
|
|
int
|
|
|
|
_sys_read_ahead (int fd)
|
|
|
|
{
|
|
|
|
child_process * cp;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (fd < 0 || fd >= MAXDESC)
|
|
|
|
return STATUS_READ_ERROR;
|
|
|
|
|
|
|
|
cp = fd_info[fd].cp;
|
|
|
|
|
|
|
|
if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
|
|
|
|
return STATUS_READ_ERROR;
|
|
|
|
|
|
|
|
if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
|
|
|
|
|| (fd_info[fd].flags & FILE_READ) == 0)
|
|
|
|
{
|
|
|
|
DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
|
|
|
|
cp->status = STATUS_READ_IN_PROGRESS;
|
|
|
|
|
|
|
|
if (fd_info[fd].flags & FILE_PIPE)
|
|
|
|
/* Use read to get CRLF translation */
|
|
|
|
rc = _read (fd, &cp->chr, sizeof (char));
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
else if (fd_info[fd].flags & FILE_SOCKET)
|
|
|
|
rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (rc == sizeof (char))
|
|
|
|
cp->status = STATUS_READ_SUCCEEDED;
|
|
|
|
else
|
|
|
|
cp->status = STATUS_READ_FAILED;
|
|
|
|
|
|
|
|
return cp->status;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sys_read (int fd, char * buffer, unsigned int count)
|
|
|
|
{
|
|
|
|
int nchars;
|
|
|
|
int extra = 0;
|
|
|
|
int to_read;
|
|
|
|
DWORD waiting;
|
|
|
|
|
|
|
|
if (fd < 0 || fd >= MAXDESC)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
|
|
|
|
{
|
|
|
|
child_process *cp = fd_info[fd].cp;
|
|
|
|
|
|
|
|
if ((fd_info[fd].flags & FILE_READ) == 0)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* presence of a child_process structure means we are operating in
|
|
|
|
non-blocking mode - otherwise we just call _read directly.
|
|
|
|
Note that the child_process structure might be missing because
|
|
|
|
reap_subprocess has been called; in this case the pipe is
|
|
|
|
already broken, so calling _read on it is okay. */
|
|
|
|
if (cp)
|
|
|
|
{
|
|
|
|
int current_status = cp->status;
|
|
|
|
|
|
|
|
switch (current_status)
|
|
|
|
{
|
|
|
|
case STATUS_READ_FAILED:
|
|
|
|
case STATUS_READ_ERROR:
|
|
|
|
/* report normal EOF */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case STATUS_READ_READY:
|
|
|
|
case STATUS_READ_IN_PROGRESS:
|
|
|
|
DebPrint (("sys_read called when read is in progress\n"));
|
|
|
|
errno = EWOULDBLOCK;
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
case STATUS_READ_SUCCEEDED:
|
|
|
|
/* consume read-ahead char */
|
|
|
|
*buffer++ = cp->chr;
|
|
|
|
count--;
|
|
|
|
extra = 1;
|
|
|
|
cp->status = STATUS_READ_ACKNOWLEDGED;
|
|
|
|
ResetEvent (cp->char_avail);
|
|
|
|
|
|
|
|
case STATUS_READ_ACKNOWLEDGED:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DebPrint (("sys_read: bad status %d\n", current_status));
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd_info[fd].flags & FILE_PIPE)
|
|
|
|
{
|
|
|
|
PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
|
|
|
|
to_read = min (waiting, (DWORD) count);
|
|
|
|
|
|
|
|
/* Use read to get CRLF translation */
|
|
|
|
nchars = _read (fd, buffer, to_read);
|
|
|
|
}
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
else /* FILE_SOCKET */
|
|
|
|
{
|
|
|
|
if (!have_winsock) abort ();
|
|
|
|
|
|
|
|
/* do the equivalent of a non-blocking read */
|
|
|
|
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
|
|
|
|
if (waiting == 0 && extra == 0)
|
|
|
|
{
|
|
|
|
h_errno = errno = EWOULDBLOCK;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nchars = 0;
|
|
|
|
if (waiting)
|
|
|
|
{
|
|
|
|
/* always use binary mode for sockets */
|
|
|
|
nchars = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
|
|
|
|
if (nchars == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
|
|
|
|
pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
|
|
|
|
if (extra == 0)
|
|
|
|
{
|
|
|
|
set_errno ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
nchars = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nchars = _read (fd, buffer, count);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nchars = _read (fd, buffer, count);
|
|
|
|
|
|
|
|
return nchars + extra;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For now, don't bother with a non-blocking mode */
|
|
|
|
int
|
|
|
|
sys_write (int fd, const void * buffer, unsigned int count)
|
|
|
|
{
|
|
|
|
int nchars;
|
|
|
|
|
|
|
|
if (fd < 0 || fd >= MAXDESC)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
|
|
|
|
if ((fd_info[fd].flags & FILE_WRITE) == 0)
|
|
|
|
{
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
if (fd_info[fd].flags & FILE_SOCKET)
|
|
|
|
{
|
|
|
|
if (!have_winsock) abort ();
|
|
|
|
nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
|
|
|
|
if (nchars == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
DebPrint(("sys_read.send failed with error %d on socket %ld\n",
|
|
|
|
pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
|
|
|
|
set_errno ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
nchars = _write (fd, buffer, count);
|
|
|
|
|
|
|
|
return nchars;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
term_ntproc ()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
/* shutdown the socket interface if necessary */
|
|
|
|
term_winsock ();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
init_ntproc ()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_SOCKETS
|
|
|
|
/* initialise the socket interface if available */
|
|
|
|
init_winsock ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Initial preparation for subprocess support: replace our standard
|
|
|
|
handles with non-inheritable versions. */
|
|
|
|
{
|
|
|
|
HANDLE parent;
|
|
|
|
HANDLE stdin_save = INVALID_HANDLE_VALUE;
|
|
|
|
HANDLE stdout_save = INVALID_HANDLE_VALUE;
|
|
|
|
HANDLE stderr_save = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
parent = GetCurrentProcess ();
|
|
|
|
|
|
|
|
/* ignore errors when duplicating and closing; typically the
|
|
|
|
handles will be invalid when running as a gui program. */
|
|
|
|
DuplicateHandle (parent,
|
|
|
|
GetStdHandle (STD_INPUT_HANDLE),
|
|
|
|
parent,
|
|
|
|
&stdin_save,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
|
|
|
|
DuplicateHandle (parent,
|
|
|
|
GetStdHandle (STD_OUTPUT_HANDLE),
|
|
|
|
parent,
|
|
|
|
&stdout_save,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
|
|
|
|
DuplicateHandle (parent,
|
|
|
|
GetStdHandle (STD_ERROR_HANDLE),
|
|
|
|
parent,
|
|
|
|
&stderr_save,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
|
|
|
|
fclose (stdin);
|
|
|
|
fclose (stdout);
|
|
|
|
fclose (stderr);
|
|
|
|
|
|
|
|
if (stdin_save != INVALID_HANDLE_VALUE)
|
|
|
|
_open_osfhandle ((long) stdin_save, O_TEXT);
|
|
|
|
else
|
|
|
|
open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
|
|
|
|
fdopen (0, "r");
|
|
|
|
|
|
|
|
if (stdout_save != INVALID_HANDLE_VALUE)
|
|
|
|
_open_osfhandle ((long) stdout_save, O_TEXT);
|
|
|
|
else
|
|
|
|
open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
|
|
|
|
fdopen (1, "w");
|
|
|
|
|
|
|
|
if (stderr_save != INVALID_HANDLE_VALUE)
|
|
|
|
_open_osfhandle ((long) stderr_save, O_TEXT);
|
|
|
|
else
|
|
|
|
open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
|
|
|
|
fdopen (2, "w");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unfortunately, atexit depends on implementation of malloc */
|
|
|
|
/* atexit (term_ntproc); */
|
|
|
|
signal (SIGABRT, term_ntproc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* end of nt.c */
|