#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/utime.h>
#include <mbstring.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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
#undef strerror
#include "lisp.h"
#include <pwd.h>
#include <grp.h>
#ifdef __GNUC__
#define _ANONYMOUS_UNION
#define _ANONYMOUS_STRUCT
#endif
#include <windows.h>
#include <shlobj.h>
#ifdef HAVE_SOCKETS
#include <sys/socket.h>
#undef socket
#undef bind
#undef connect
#undef htons
#undef ntohs
#undef inet_addr
#undef gethostname
#undef gethostbyname
#undef getservbyname
#undef getpeername
#undef shutdown
#undef setsockopt
#undef listen
#undef getsockname
#undef accept
#undef recvfrom
#undef sendto
#endif
#include "w32.h"
#include "ndir.h"
#include "w32heap.h"
#include "systime.h"
typedef HRESULT (WINAPI * ShGetFolderPath_fn)
(IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
void globals_of_w32 ();
extern Lisp_Object Vw32_downcase_file_names;
extern Lisp_Object Vw32_generate_fake_inodes;
extern Lisp_Object Vw32_get_true_file_attributes;
extern int w32_num_mouse_buttons;
static BOOL g_b_init_is_windows_9x;
static BOOL g_b_init_open_process_token;
static BOOL g_b_init_get_token_information;
static BOOL g_b_init_lookup_account_sid;
static BOOL g_b_init_get_sid_identifier_authority;
typedef BOOL (WINAPI * OpenProcessToken_Proc) (
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle);
typedef BOOL (WINAPI * GetTokenInformation_Proc) (
HANDLE TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation,
DWORD TokenInformationLength,
PDWORD ReturnLength);
#ifdef _UNICODE
const char * const LookupAccountSid_Name = "LookupAccountSidW";
#else
const char * const LookupAccountSid_Name = "LookupAccountSidA";
#endif
typedef BOOL (WINAPI * LookupAccountSid_Proc) (
LPCTSTR lpSystemName,
PSID Sid,
LPTSTR Name,
LPDWORD cbName,
LPTSTR DomainName,
LPDWORD cbDomainName,
PSID_NAME_USE peUse);
typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
PSID pSid);
static BOOL
is_windows_9x ()
{
static BOOL s_b_ret=0;
OSVERSIONINFO os_ver;
if (g_b_init_is_windows_9x == 0)
{
g_b_init_is_windows_9x = 1;
ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx (&os_ver))
{
s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
}
}
return s_b_ret;
}
BOOL WINAPI open_process_token (
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle)
{
static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
return FALSE;
}
if (g_b_init_open_process_token == 0)
{
g_b_init_open_process_token = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Open_Process_Token =
(OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
}
if (s_pfn_Open_Process_Token == NULL)
{
return FALSE;
}
return (
s_pfn_Open_Process_Token (
ProcessHandle,
DesiredAccess,
TokenHandle)
);
}
BOOL WINAPI get_token_information (
HANDLE TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation,
DWORD TokenInformationLength,
PDWORD ReturnLength)
{
static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
return FALSE;
}
if (g_b_init_get_token_information == 0)
{
g_b_init_get_token_information = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Get_Token_Information =
(GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
}
if (s_pfn_Get_Token_Information == NULL)
{
return FALSE;
}
return (
s_pfn_Get_Token_Information (
TokenHandle,
TokenInformationClass,
TokenInformation,
TokenInformationLength,
ReturnLength)
);
}
BOOL WINAPI lookup_account_sid (
LPCTSTR lpSystemName,
PSID Sid,
LPTSTR Name,
LPDWORD cbName,
LPTSTR DomainName,
LPDWORD cbDomainName,
PSID_NAME_USE peUse)
{
static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
return FALSE;
}
if (g_b_init_lookup_account_sid == 0)
{
g_b_init_lookup_account_sid = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Lookup_Account_Sid =
(LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
}
if (s_pfn_Lookup_Account_Sid == NULL)
{
return FALSE;
}
return (
s_pfn_Lookup_Account_Sid (
lpSystemName,
Sid,
Name,
cbName,
DomainName,
cbDomainName,
peUse)
);
}
PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
PSID pSid)
{
static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
return NULL;
}
if (g_b_init_get_sid_identifier_authority == 0)
{
g_b_init_get_sid_identifier_authority = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Get_Sid_Identifier_Authority =
(GetSidIdentifierAuthority_Proc) GetProcAddress (
hm_advapi32, "GetSidIdentifierAuthority");
}
if (s_pfn_Get_Sid_Identifier_Authority == NULL)
{
return NULL;
}
return (s_pfn_Get_Sid_Identifier_Authority (pSid));
}
char *
w32_strerror (int error_no)
{
static char buf[500];
if (error_no == 0)
error_no = GetLastError ();
buf[0] = '\0';
if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
error_no,
0,
buf, sizeof (buf), NULL))
sprintf (buf, "w32 error %u", error_no);
return buf;
}
int
w32_valid_pointer_p (void *p, int size)
{
SIZE_T done;
HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
if (h)
{
unsigned char *buf = alloca (size);
int retval = ReadProcessMemory (h, p, buf, size, &done);
CloseHandle (h);
return retval;
}
else
return -1;
}
static char startup_dir[MAXPATHLEN];
char *
getwd (char *dir)
{
#if 0
if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
return dir;
return NULL;
#else
strcpy (dir, startup_dir);
return dir;
#endif
}
#ifndef HAVE_SOCKETS
int
gethostname (char *buffer, int size)
{
return !GetComputerName (buffer, &size);
}
#endif
int
getloadavg (double loadavg[], int nelem)
{
int i;
for (i = 0; i < nelem; i++)
{
loadavg[i] = 0.0;
}
return i;
}
#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];
static struct passwd the_passwd =
{
the_passwd_name,
the_passwd_passwd,
0,
0,
0,
the_passwd_gecos,
the_passwd_dir,
the_passwd_shell,
};
static struct group the_group =
{
"root",
};
int
getuid ()
{
return the_passwd.pw_uid;
}
int
geteuid ()
{
return getuid ();
}
int
getgid ()
{
return the_passwd.pw_gid;
}
int
getegid ()
{
return getgid ();
}
struct passwd *
getpwuid (int uid)
{
if (uid == the_passwd.pw_uid)
return &the_passwd;
return NULL;
}
struct group *
getgrgid (gid_t gid)
{
return &the_group;
}
struct passwd *
getpwnam (char *name)
{
struct passwd *pw;
pw = getpwuid (getuid ());
if (!pw)
return pw;
if (stricmp (name, pw->pw_name))
return NULL;
return pw;
}
void
init_user_info ()
{
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 (
open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
&& get_token_information (
token, TokenUser,
(PVOID) user_sid, sizeof (user_sid), &trash)
&& lookup_account_sid (
NULL, *((PSID *) user_sid), name, &length,
domain, &dlength, &user_type)
)
{
strcpy (the_passwd.pw_name, name);
if (stricmp ("administrator", name) == 0)
{
the_passwd.pw_uid = 0;
the_passwd.pw_gid = 0;
}
else
{
SID_IDENTIFIER_AUTHORITY * pSIA;
pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
(pSIA->Value[3] << 16) +
(pSIA->Value[4] << 8) +
(pSIA->Value[5] << 0));
the_passwd.pw_uid = the_passwd.pw_uid % 60001;
if (get_token_information (token, TokenPrimaryGroup,
(PVOID) user_sid, sizeof (user_sid), &trash))
{
SID_IDENTIFIER_AUTHORITY * pSIA;
pSIA = get_sid_identifier_authority (*((PSID *) user_sid));
the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
(pSIA->Value[3] << 16) +
(pSIA->Value[4] << 8) +
(pSIA->Value[5] << 0));
the_passwd.pw_gid = the_passwd.pw_gid % 60001;
}
else
the_passwd.pw_gid = the_passwd.pw_uid;
}
}
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;
}
if (getenv ("HOME") == NULL)
abort ();
if (getenv ("SHELL") == NULL)
abort ();
strcpy (the_passwd.pw_dir, getenv ("HOME"));
strcpy (the_passwd.pw_shell, getenv ("SHELL"));
if (token)
CloseHandle (token);
}
int
random ()
{
return ((rand () << 15) | rand ());
}
void
srandom (int seed)
{
srand (seed);
}
static void
normalize_filename (fp, path_sep)
register char *fp;
char path_sep;
{
char sep;
char *elem;
if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
{
*fp += 'a' - 'A';
fp += 2;
}
if (NILP (Vw32_downcase_file_names))
{
while (*fp)
{
if (*fp == '/' || *fp == '\\')
*fp = path_sep;
fp++;
}
return;
}
sep = path_sep;
elem = fp;
do {
if (*fp >= 'a' && *fp <= 'z')
elem = 0;
if (*fp == 0 || *fp == ':')
{
sep = *fp;
*fp = '/';
}
if (*fp == '/' || *fp == '\\')
{
if (elem && elem != fp)
{
*fp = 0;
_strlwr (elem);
}
*fp = sep;
elem = fp + 1;
sep = path_sep;
}
} while (*fp++);
}
void
dostounix_filename (p)
register char *p;
{
normalize_filename (p, '/');
}
void
unixtodos_filename (p)
register char *p;
{
normalize_filename (p, '\\');
}
int
crlf_to_lf (n, buf)
register int n;
register unsigned char *buf;
{
unsigned char *np = buf;
unsigned char *startp = buf;
unsigned char *endp = buf + n;
if (n == 0)
return n;
while (buf < endp - 1)
{
if (*buf == 0x0d)
{
if (*(++buf) != 0x0a)
*np++ = 0x0d;
}
else
*np++ = *buf++;
}
if (buf < endp)
*np++ = *buf++;
return np - startp;
}
static int
parse_root (char * name, char ** pPath)
{
char * start = name;
if (name == NULL)
return 0;
if (isalpha (name[0]) && name[1] == ':')
{
name += 2;
if (IS_DIRECTORY_SEP (name[0]))
name++;
}
else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
{
int slashes = 2;
name += 2;
do
{
if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break;
name++;
}
while ( *name );
if (IS_DIRECTORY_SEP (name[0]))
name++;
}
if (pPath)
*pPath = name;
return name - start;
}
static int
get_long_basename (char * name, char * buf, int size)
{
WIN32_FIND_DATA find_data;
HANDLE dir_handle;
int len = 0;
if (_mbspbrk (name, "*?|<>\""))
return 0;
dir_handle = FindFirstFile (name, &find_data);
if (dir_handle != INVALID_HANDLE_VALUE)
{
if ((len = strlen (find_data.cFileName)) < size)
memcpy (buf, find_data.cFileName, len + 1);
else
len = 0;
FindClose (dir_handle);
}
return len;
}
BOOL
w32_get_long_filename (char * name, char * buf, int size)
{
char * o = buf;
char * p;
char * q;
char full[ MAX_PATH ];
int len;
len = strlen (name);
if (len >= MAX_PATH)
return FALSE;
memcpy (full, name, len+1);
unixtodos_filename (full);
len = parse_root (full, &p);
memcpy (o, full, len);
o += len;
*o = '\0';
size -= len;
while (p != NULL && *p)
{
q = p;
p = strchr (q, '\\');
if (p) *p = '\0';
len = get_long_basename (full, o, size);
if (len > 0)
{
o += len;
size -= len;
if (p != NULL)
{
*p++ = '\\';
if (size < 2)
return FALSE;
*o++ = '\\';
size--;
*o = '\0';
}
}
else
return FALSE;
}
return TRUE;
}
int
is_unc_volume (const char *filename)
{
const char *ptr = filename;
if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
return 0;
if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
return 0;
return 1;
}
int
sigsetmask (int signal_mask)
{
return 0;
}
int
sigmask (int sig)
{
return 0;
}
int
sigblock (int sig)
{
return 0;
}
int
sigunblock (int sig)
{
return 0;
}
int
setpgrp (int pid, int gid)
{
return 0;
}
int
alarm (int seconds)
{
return 0;
}
void
unrequest_sigio (void)
{
return;
}
void
request_sigio (void)
{
return;
}
#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
LPBYTE
w32_get_resource (key, lpdwtype)
char *key;
LPDWORD lpdwtype;
{
LPBYTE lpvalue;
HKEY hrootkey = NULL;
DWORD cbData;
BOOL ok = FALSE;
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);
}
char *get_emacs_configuration (void);
extern Lisp_Object Vsystem_configuration;
void
init_environment (char ** argv)
{
static const char * const tempdirs[] = {
"$TMPDIR", "$TEMP", "$TMP", "c:/"
};
int i;
const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
for (i = 0; i < imax ; i++)
{
const char *tmp = tempdirs[i];
if (*tmp == '$')
tmp = getenv (tmp + 1);
if (tmp && _access (tmp, D_OK) == 0)
{
char * var = alloca (strlen (tmp) + 8);
sprintf (var, "TMPDIR=%s", tmp);
_putenv (strdup (var));
break;
}
}
if (i >= imax)
cmd_error_internal
(Fcons (Qerror,
Fcons (build_string ("no usable temporary directories found!!"),
Qnil)),
"While setting TMPDIR: ");
{
int i;
LPBYTE lpval;
DWORD dwType;
char locale_name[32];
struct stat ignored;
char default_home[MAX_PATH];
static const struct env_entry
{
char * name;
char * def_value;
} dflt_envvars[] =
{
{"HOME", "C:/"},
{"PRELOAD_WINSOCK", NULL},
{"emacs_dir", "C:/emacs"},
{"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
{"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
{"EMACSDATA", "%emacs_dir%/etc"},
{"EMACSPATH", "%emacs_dir%/bin"},
{"EMACSDOC", "%emacs_dir%/etc"},
{"TERM", "cmd"},
{"LANG", NULL},
};
#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
struct env_entry env_vars[N_ENV_VARS];
for (i = 0; i < N_ENV_VARS; i++)
env_vars[i] = dflt_envvars[i];
if (stat ("C:/.emacs", &ignored) < 0)
{
HRESULT profile_result;
HMODULE shell32_dll;
ShGetFolderPath_fn get_folder_path;
shell32_dll = GetModuleHandle ("shell32.dll");
get_folder_path = (ShGetFolderPath_fn)
GetProcAddress (shell32_dll, "SHGetFolderPathA");
if (get_folder_path != NULL)
{
profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
0, default_home);
if (profile_result == S_OK)
env_vars[0].def_value = default_home;
}
FreeLibrary (shell32_dll);
}
if (GetLocaleInfo (LOCALE_USER_DEFAULT,
LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
locale_name, sizeof (locale_name)))
{
for (i = 0; i < N_ENV_VARS; i++)
{
if (strcmp (env_vars[i].name, "LANG") == 0)
{
env_vars[i].def_value = locale_name;
break;
}
}
}
#define SET_ENV_BUF_SIZE (4 * MAX_PATH)
{
char *p;
char modname[MAX_PATH];
if (!GetModuleFileName (NULL, modname, MAX_PATH))
abort ();
if ((p = strrchr (modname, '\\')) == NULL)
abort ();
*p = 0;
if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
{
char buf[SET_ENV_BUF_SIZE];
*p = 0;
for (p = modname; *p; p++)
if (*p == '\\') *p = '/';
_snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
_putenv (strdup (buf));
}
else if (p && stricmp (p, "\\i386") == 0)
{
*p = 0;
p = strrchr (modname, '\\');
if (p != NULL)
{
*p = 0;
p = strrchr (modname, '\\');
if (p && stricmp (p, "\\src") == 0)
{
char buf[SET_ENV_BUF_SIZE];
*p = 0;
for (p = modname; *p; p++)
if (*p == '\\') *p = '/';
_snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
_putenv (strdup (buf));
}
}
}
}
for (i = 0; i < N_ENV_VARS; i++)
{
if (!getenv (env_vars[i].name))
{
int dont_free = 0;
if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL)
{
lpval = env_vars[i].def_value;
dwType = REG_EXPAND_SZ;
dont_free = 1;
}
if (lpval)
{
char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
if (dwType == REG_EXPAND_SZ)
ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
else if (dwType == REG_SZ)
strcpy (buf1, lpval);
if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
{
_snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
buf1);
_putenv (strdup (buf2));
}
if (!dont_free)
xfree (lpval);
}
}
}
}
Vsystem_configuration = build_string (EMACS_CONFIGURATION);
{
char ** envp;
for (envp = environ; *envp; envp++)
if (_strnicmp (*envp, "PATH=", 5) == 0)
memcpy (*envp, "PATH=", 5);
else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
memcpy (*envp, "COMSPEC=", 8);
}
if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
abort ();
{
char *p;
static char modname[MAX_PATH];
if (!GetModuleFileName (NULL, modname, MAX_PATH))
abort ();
if ((p = strrchr (modname, '\\')) == NULL)
abort ();
*p = 0;
SetCurrentDirectory (modname);
*p = '\\';
argv[0] = modname;
}
w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
init_user_info ();
}
char *
emacs_root_dir (void)
{
static char root_dir[FILENAME_MAX];
const char *p;
p = getenv ("emacs_dir");
if (p == NULL)
abort ();
strcpy (root_dir, p);
root_dir[parse_root (root_dir, NULL)] = '\0';
dostounix_filename (root_dir);
return root_dir;
}
char *
get_emacs_configuration (void)
{
char *arch, *oem, *os;
int build_num;
static char configuration_buffer[32];
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;
}
#ifdef _MSC_VER
#define COMPILER_NAME "msvc"
#else
#ifdef __GNUC__
#define COMPILER_NAME "mingw"
#else
#define COMPILER_NAME "unknown"
#endif
#endif
oem = COMPILER_NAME;
switch (osinfo_cache.dwPlatformId) {
case VER_PLATFORM_WIN32_NT:
os = "nt";
build_num = osinfo_cache.dwBuildNumber;
break;
case VER_PLATFORM_WIN32_WINDOWS:
if (osinfo_cache.dwMinorVersion == 0) {
os = "windows95";
} else {
os = "windows98";
}
build_num = LOWORD (osinfo_cache.dwBuildNumber);
break;
case VER_PLATFORM_WIN32s:
os = "windows32s";
build_num = LOWORD (osinfo_cache.dwBuildNumber);
break;
default:
os = "unknown";
build_num = 0;
break;
}
if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
get_w32_major_version (), get_w32_minor_version (), build_num);
} else {
sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
}
return configuration_buffer;
}
char *
get_emacs_configuration_options (void)
{
static char options_buffer[256];
#ifdef _MSC_VER
#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
#else
#ifdef __GNUC__
#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
#else
#define COMPILER_VERSION ""
#endif
#endif
sprintf (options_buffer, COMPILER_VERSION);
#ifdef EMACSDEBUG
strcat (options_buffer, " --no-opt");
#endif
#ifdef USER_CFLAGS
strcat (options_buffer, " --cflags");
strcat (options_buffer, USER_CFLAGS);
#endif
#ifdef USER_LDFLAGS
strcat (options_buffer, " --ldflags");
strcat (options_buffer, USER_LDFLAGS);
#endif
return options_buffer;
}
#include <sys/timeb.h>
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;
tz->tz_dsttime = tb.dstflag;
}
}
char *
sys_ctime (const time_t *t)
{
char *str = (char *) ctime (t);
return (str ? str : "Sun Jan 01 00:00:00 1970");
}
void
sys_sleep (int seconds)
{
Sleep (seconds * 1000);
}
extern int __cdecl _set_osfhnd (int fd, long h);
extern int __cdecl _free_osfhnd (int fd);
filedesc fd_info [ MAXDESC ];
typedef struct volume_info_data {
struct volume_info_data * next;
DWORD timestamp;
char * root_dir;
DWORD serialnum;
DWORD maxcomp;
DWORD flags;
char * name;
char * type;
} volume_info_data;
static volume_info_data volume_info;
static BOOL fixed_drives[26];
#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
#define VOLINFO_STILL_VALID( root_dir, info ) \
( ( isalpha (root_dir[0]) && \
fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
|| GetTickCount () - info->timestamp < 10000 )
static volume_info_data *volume_cache = NULL;
static volume_info_data *
lookup_volume_info (char * root_dir)
{
volume_info_data * info;
for (info = volume_cache; info; info = info->next)
if (stricmp (info->root_dir, root_dir) == 0)
break;
return info;
}
static void
add_volume_info (char * root_dir, volume_info_data * info)
{
info->root_dir = xstrdup (root_dir);
info->next = volume_cache;
volume_cache = info;
}
volume_info_data *
GetCachedVolumeInformation (char * root_dir)
{
volume_info_data * info;
char default_root[ MAX_PATH ];
if (root_dir == NULL)
{
if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
return NULL;
parse_root (default_root, &root_dir);
*root_dir = 0;
root_dir = default_root;
}
#if 0
if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
{
char remote_name[ 256 ];
char drive[3] = { root_dir[0], ':' };
if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
== NO_ERROR)
;
}
#endif
info = lookup_volume_info (root_dir);
if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
{
char name[ 256 ];
DWORD serialnum;
DWORD maxcomp;
DWORD flags;
char type[ 256 ];
if (!GetVolumeInformation (root_dir,
name, sizeof (name),
&serialnum,
&maxcomp,
&flags,
type, sizeof (type)))
return NULL;
if (info == NULL)
{
info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
add_volume_info (root_dir, info);
}
else
{
xfree (info->name);
xfree (info->type);
}
info->name = xstrdup (name);
info->serialnum = serialnum;
info->maxcomp = maxcomp;
info->flags = flags;
info->type = xstrdup (type);
info->timestamp = GetTickCount ();
}
return info;
}
int
get_volume_info (const char * name, const char ** pPath)
{
char temp[MAX_PATH];
char *rootname = NULL;
volume_info_data * info;
if (name == NULL)
return FALSE;
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]))
{
char *str = temp;
int slashes = 4;
rootname = temp;
do
{
if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break;
*str++ = *name++;
}
while ( *name );
*str++ = '\\';
*str = 0;
}
if (pPath)
*pPath = name;
info = GetCachedVolumeInformation (rootname);
if (info != NULL)
{
volume_info = *info;
return TRUE;
}
return FALSE;
}
int
is_fat_volume (const char * name, const char ** pPath)
{
if (get_volume_info (name, pPath))
return (volume_info.maxcomp == 12);
return FALSE;
}
const char *
map_w32_filename (const char * name, const char ** pPath)
{
static char shortname[MAX_PATH];
char * str = shortname;
char c;
char * path;
const char * save_name = name;
if (strlen (name) >= MAX_PATH)
{
strcpy (shortname, "?");
return shortname;
}
if (is_fat_volume (name, (const char **)&path))
{
register int left = 8;
register int extn = 0;
register int dots = 2;
while (name < path)
*str++ = *name++;
while ((c = *name++))
{
switch ( c )
{
case '\\':
case '/':
*str++ = '\\';
extn = 0;
dots = 2;
left = 8;
break;
case ':':
*str++ = ':';
extn = 0;
dots = 2;
left = 8;
break;
case '.':
if ( dots )
{
if (! *name ||
*name == '.' ||
IS_DIRECTORY_SEP (*name))
{
*str++ = '.';
dots--;
}
else
{
*str++ = '_';
left--;
dots = 0;
}
}
else if ( !extn )
{
*str++ = '.';
extn = 1;
left = 3;
}
else
{
*str++ = '_';
}
break;
case '~':
case '#':
if ( ! left )
str[-1] = c;
default:
if ( left )
{
*str++ = tolower (c);
left--;
dots = 0;
}
break;
}
}
*str = '\0';
}
else
{
strcpy (shortname, name);
unixtodos_filename (shortname);
}
if (pPath)
*pPath = shortname + (path - save_name);
return shortname;
}
static int
is_exec (const char * name)
{
char * p = strrchr (name, '.');
return
(p != NULL
&& (stricmp (p, ".exe") == 0 ||
stricmp (p, ".com") == 0 ||
stricmp (p, ".bat") == 0 ||
stricmp (p, ".cmd") == 0));
}
struct direct dir_static;
static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
static int dir_is_fat;
static char dir_pathname[MAXPATHLEN+1];
static WIN32_FIND_DATA dir_find_data;
static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
HANDLE open_unc_volume (const char *);
char *read_unc_volume (HANDLE, char *, int);
void close_unc_volume (HANDLE);
DIR *
opendir (char *filename)
{
DIR *dirp;
if (dir_find_handle != INVALID_HANDLE_VALUE)
return NULL;
if (wnet_enum_handle != INVALID_HANDLE_VALUE)
return NULL;
if (is_unc_volume (filename))
{
wnet_enum_handle = open_unc_volume (filename);
if (wnet_enum_handle == INVALID_HANDLE_VALUE)
return NULL;
}
if (!(dirp = (DIR *) malloc (sizeof (DIR))))
return NULL;
dirp->dd_fd = 0;
dirp->dd_loc = 0;
dirp->dd_size = 0;
strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
dir_pathname[MAXPATHLEN] = '\0';
dir_is_fat = is_fat_volume (filename, NULL);
return dirp;
}
void
closedir (DIR *dirp)
{
if (dir_find_handle != INVALID_HANDLE_VALUE)
{
FindClose (dir_find_handle);
dir_find_handle = INVALID_HANDLE_VALUE;
}
else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
{
close_unc_volume (wnet_enum_handle);
wnet_enum_handle = INVALID_HANDLE_VALUE;
}
xfree ((char *) dirp);
}
struct direct *
readdir (DIR *dirp)
{
if (wnet_enum_handle != INVALID_HANDLE_VALUE)
{
if (!read_unc_volume (wnet_enum_handle,
dir_find_data.cFileName,
MAX_PATH))
return NULL;
}
else if (dir_find_handle == INVALID_HANDLE_VALUE)
{
char filename[MAXNAMLEN + 3];
int ln;
strcpy (filename, dir_pathname);
ln = strlen (filename) - 1;
if (!IS_DIRECTORY_SEP (filename[ln]))
strcat (filename, "\\");
strcat (filename, "*");
dir_find_handle = FindFirstFile (filename, &dir_find_data);
if (dir_find_handle == INVALID_HANDLE_VALUE)
return NULL;
}
else
{
if (!FindNextFile (dir_find_handle, &dir_find_data))
return NULL;
}
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 (dir_find_data.cFileName);
strcpy (dir_static.d_name, dir_find_data.cFileName);
if (dir_is_fat)
_strlwr (dir_static.d_name);
else if (!NILP (Vw32_downcase_file_names))
{
register char *p;
for (p = dir_static.d_name; *p; p++)
if (*p >= 'a' && *p <= 'z')
break;
if (!*p)
_strlwr (dir_static.d_name);
}
return &dir_static;
}
HANDLE
open_unc_volume (const char *path)
{
NETRESOURCE nr;
HANDLE henum;
int result;
nr.dwScope = RESOURCE_GLOBALNET;
nr.dwType = RESOURCETYPE_DISK;
nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
nr.dwUsage = RESOURCEUSAGE_CONTAINER;
nr.lpLocalName = NULL;
nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
nr.lpComment = NULL;
nr.lpProvider = NULL;
result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
if (result == NO_ERROR)
return henum;
else
return INVALID_HANDLE_VALUE;
}
char *
read_unc_volume (HANDLE henum, char *readbuf, int size)
{
DWORD count;
int result;
DWORD bufsize = 512;
char *buffer;
char *ptr;
count = 1;
buffer = alloca (bufsize);
result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
if (result != NO_ERROR)
return NULL;
ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
ptr += 2;
while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
ptr++;
strncpy (readbuf, ptr, size);
return readbuf;
}
void
close_unc_volume (HANDLE henum)
{
if (henum != INVALID_HANDLE_VALUE)
WNetCloseEnum (henum);
}
DWORD
unc_volume_file_attributes (const char *path)
{
HANDLE henum;
DWORD attrs;
henum = open_unc_volume (path);
if (henum == INVALID_HANDLE_VALUE)
return -1;
attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
close_unc_volume (henum);
return attrs;
}
int
sys_access (const char * path, int mode)
{
DWORD attributes;
path = map_w32_filename (path, NULL);
if (is_unc_volume (path))
{
attributes = unc_volume_file_attributes (path);
if (attributes == -1) {
errno = EACCES;
return -1;
}
}
else if ((attributes = GetFileAttributes (path)) == -1)
{
errno = EACCES;
return -1;
}
if ((mode & X_OK) != 0 && !is_exec (path))
{
errno = EACCES;
return -1;
}
if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
{
errno = EACCES;
return -1;
}
if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
errno = EACCES;
return -1;
}
return 0;
}
int
sys_chdir (const char * path)
{
return _chdir (map_w32_filename (path, NULL));
}
int
sys_chmod (const char * path, int mode)
{
return _chmod (map_w32_filename (path, NULL), mode);
}
int
sys_chown (const char *path, uid_t owner, gid_t group)
{
if (sys_chmod (path, _S_IREAD) == -1)
return -1;
return 0;
}
int
sys_creat (const char * path, int mode)
{
return _creat (map_w32_filename (path, NULL), mode);
}
FILE *
sys_fopen(const char * path, const char * mode)
{
int fd;
int oflag;
const char * mode_save = mode;
if (mode[0] == 'r')
oflag = O_RDONLY;
else if (mode[0] == 'w' || mode[0] == 'a')
oflag = O_WRONLY | O_CREAT | O_TRUNC;
else
return NULL;
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_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
if (fd < 0)
return NULL;
return _fdopen (fd, mode_save);
}
int
sys_link (const char * old, const char * new)
{
HANDLE fileh;
int result = -1;
char oldname[MAX_PATH], newname[MAX_PATH];
if (old == NULL || new == NULL)
{
errno = ENOENT;
return -1;
}
strcpy (oldname, map_w32_filename (old, NULL));
strcpy (newname, map_w32_filename (new, NULL));
fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (fileh != INVALID_HANDLE_VALUE)
{
int wlen;
struct {
WIN32_STREAM_ID wid;
WCHAR wbuffer[MAX_PATH];
} data;
wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
data.wid.cStreamName, MAX_PATH);
if (wlen > 0)
{
LPVOID context = NULL;
DWORD wbytes = 0;
data.wid.dwStreamId = BACKUP_LINK;
data.wid.dwStreamAttributes = 0;
data.wid.Size.LowPart = wlen * sizeof(WCHAR);
data.wid.Size.HighPart = 0;
data.wid.dwStreamNameSize = 0;
if (BackupWrite (fileh, (LPBYTE)&data,
offsetof (WIN32_STREAM_ID, cStreamName)
+ data.wid.Size.LowPart,
&wbytes, FALSE, FALSE, &context)
&& BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
{
result = 0;
}
else
{
errno = EINVAL; }
}
CloseHandle (fileh);
}
else
errno = ENOENT;
return result;
}
int
sys_mkdir (const char * path)
{
return _mkdir (map_w32_filename (path, NULL));
}
char *
sys_mktemp (char * template)
{
char * p;
int i;
unsigned uid = GetCurrentThreadId ();
static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
if (template == NULL)
return NULL;
p = template + strlen (template);
i = 5;
while (--p >= template && p[0] == 'X' && --i >= 0)
{
p[0] = '0' + uid % 10;
uid /= 10;
}
if (i < 0 && p[0] == 'X')
{
i = 0;
do
{
int save_errno = errno;
p[0] = first_char[i];
if (sys_access (template, 0) < 0)
{
errno = save_errno;
return template;
}
}
while (++i < sizeof (first_char));
}
template[0] = 0;
return template;
}
int
sys_open (const char * path, int oflag, int mode)
{
const char* mpath = map_w32_filename (path, NULL);
int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
if (res >= 0)
return res;
return _open (mpath, oflag | _O_NOINHERIT, mode);
}
int
sys_rename (const char * oldname, const char * newname)
{
BOOL result;
char temp[MAX_PATH];
strcpy (temp, map_w32_filename (oldname, NULL));
if (os_subtype == OS_WIN95)
{
char * o;
char * p;
int i = 0;
oldname = map_w32_filename (oldname, NULL);
if (o = strrchr (oldname, '\\'))
o++;
else
o = (char *) oldname;
if (p = strrchr (temp, '\\'))
p++;
else
p = temp;
do
{
sprintf (p, "_.%s.%u", o, i);
i++;
result = rename (oldname, temp);
}
while (result < 0 && errno == EEXIST);
if (result < 0)
return -1;
}
newname = map_w32_filename (newname, NULL);
result = rename (temp, newname);
if (result < 0
&& errno == EEXIST
&& _chmod (newname, 0666) == 0
&& _unlink (newname) == 0)
result = rename (temp, newname);
return result;
}
int
sys_rmdir (const char * path)
{
return _rmdir (map_w32_filename (path, NULL));
}
int
sys_unlink (const char * path)
{
path = map_w32_filename (path, NULL);
_chmod (path, 0666);
return _unlink (path);
}
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)
{
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.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
init = 1;
}
if (CompareFileTime (&ft, &utc_base_ft) < 0)
return 0;
ret = (long double) ft.dwHighDateTime
* 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
ret -= utc_base;
return (time_t) (ret * 1e-7L);
}
void
convert_from_time_t (time_t time, FILETIME * pft)
{
long double tmp;
if (!init)
{
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;
}
tmp = (long double) time * 1e7 + utc_base;
pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
}
#if 0
static unsigned
hashval (const unsigned char * str)
{
unsigned h = 0;
while (*str)
{
h = (h << 4) + *str++;
h ^= (h >> 28);
}
return h;
}
static DWORD
generate_inode_val (const char * name)
{
char fullname[ MAX_PATH ];
char * p;
unsigned hash;
if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
abort ();
parse_root (fullname, &p);
_strlwr (p);
return hashval (p);
}
#endif
int
stat (const char * path, struct stat * buf)
{
char *name, *r;
WIN32_FIND_DATA wfd;
HANDLE fh;
DWORD fake_inode;
int permission;
int len;
int rootdir = FALSE;
if (path == NULL || buf == NULL)
{
errno = EFAULT;
return -1;
}
name = (char *) map_w32_filename (path, &path);
if (_mbspbrk (name, "*?|<>\""))
{
errno = ENOENT;
return -1;
}
r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
{
r[1] = r[2] = '\0';
}
len = strlen (name);
rootdir = (path >= name + len - 1
&& (IS_DIRECTORY_SEP (*path) || *path == 0));
name = strcpy (alloca (len + 2), name);
if (is_unc_volume (name))
{
DWORD attrs = unc_volume_file_attributes (name);
if (attrs == -1)
return -1;
memset (&wfd, 0, sizeof (wfd));
wfd.dwFileAttributes = attrs;
wfd.ftCreationTime = utc_base_ft;
wfd.ftLastAccessTime = utc_base_ft;
wfd.ftLastWriteTime = utc_base_ft;
strcpy (wfd.cFileName, name);
}
else 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;
len = strlen (dir_pathname);
if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
len--;
if (dir_find_handle != INVALID_HANDLE_VALUE
&& strnicmp (name, dir_pathname, len) == 0
&& IS_DIRECTORY_SEP (name[len])
&& stricmp (name + len + 1, dir_static.d_name) == 0)
{
wfd = dir_find_data;
}
else
{
fh = FindFirstFile (name, &wfd);
if (fh == INVALID_HANDLE_VALUE)
{
errno = ENOENT;
return -1;
}
FindClose (fh);
}
}
if (!NILP (Vw32_get_true_file_attributes)
&& (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL))
!= INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION info;
if (GetFileInformationByHandle (fh, &info))
{
buf->st_nlink = info.nNumberOfLinks;
fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
}
else
{
buf->st_nlink = 1;
fake_inode = 0;
}
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
buf->st_mode = _S_IFDIR;
}
else
{
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;
}
}
CloseHandle (fh);
}
else
{
buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
_S_IFDIR : _S_IFREG;
buf->st_nlink = 1;
fake_inode = 0;
}
#if 0
if (!NILP (Vw32_generate_fake_inodes))
fake_inode = generate_inode_val (name);
else if (fake_inode == 0)
{
static DWORD gen_num = 0;
fake_inode = ++gen_num;
}
#endif
if (sizeof (buf->st_ino) == 2)
buf->st_ino = fake_inode ^ (fake_inode >> 16);
else
buf->st_ino = fake_inode;
buf->st_uid = the_passwd.pw_uid;
buf->st_gid = the_passwd.pw_gid;
buf->st_dev = volume_info.serialnum;
buf->st_rdev = volume_info.serialnum;
buf->st_size = wfd.nFileSizeLow;
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;
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 if (is_exec (name))
permission |= _S_IEXEC;
buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
return 0;
}
int
fstat (int desc, struct stat * buf)
{
HANDLE fh = (HANDLE) _get_osfhandle (desc);
BY_HANDLE_FILE_INFORMATION info;
DWORD fake_inode;
int permission;
switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
{
case FILE_TYPE_DISK:
buf->st_mode = _S_IFREG;
if (!GetFileInformationByHandle (fh, &info))
{
errno = EACCES;
return -1;
}
break;
case FILE_TYPE_PIPE:
buf->st_mode = _S_IFIFO;
goto non_disk;
case FILE_TYPE_CHAR:
case FILE_TYPE_UNKNOWN:
default:
buf->st_mode = _S_IFCHR;
non_disk:
memset (&info, 0, sizeof (info));
info.dwFileAttributes = 0;
info.ftCreationTime = utc_base_ft;
info.ftLastAccessTime = utc_base_ft;
info.ftLastWriteTime = utc_base_ft;
}
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
buf->st_mode = _S_IFDIR;
buf->st_nlink = info.nNumberOfLinks;
fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
if (sizeof (buf->st_ino) == 2)
buf->st_ino = fake_inode ^ (fake_inode >> 16);
else
buf->st_ino = fake_inode;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_dev = info.dwVolumeSerialNumber;
buf->st_rdev = info.dwVolumeSerialNumber;
buf->st_size = info.nFileSizeLow;
buf->st_mtime = convert_time (info.ftLastWriteTime);
buf->st_atime = convert_time (info.ftLastAccessTime);
if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
buf->st_ctime = convert_time (info.ftCreationTime);
if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
permission = _S_IREAD;
else
permission = _S_IREAD | _S_IWRITE;
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
permission |= _S_IEXEC;
else
{
#if 0
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;
#endif
}
buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
return 0;
}
int
utime (const char *name, struct utimbuf *times)
{
struct utimbuf deftime;
HANDLE fh;
FILETIME mtime;
FILETIME atime;
if (times == NULL)
{
deftime.modtime = deftime.actime = time (NULL);
times = &deftime;
}
fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, NULL);
if (fh)
{
convert_from_time_t (times->actime, &atime);
convert_from_time_t (times->modtime, &mtime);
if (!SetFileTime (fh, NULL, &atime, &mtime))
{
CloseHandle (fh);
errno = EACCES;
return -1;
}
CloseHandle (fh);
}
else
{
errno = EINVAL;
return -1;
}
return 0;
}
#ifdef HAVE_SOCKETS
int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
void (PASCAL *pfn_WSASetLastError) (int iError);
int (PASCAL *pfn_WSAGetLastError) (void);
int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
HANDLE (PASCAL *pfn_WSACreateEvent) (void);
int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
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);
int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
const char * optval, int optlen);
int (PASCAL *pfn_listen) (SOCKET s, int backlog);
int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
int * namelen);
SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
struct sockaddr * from, int * fromlen);
int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
const struct sockaddr * to, int tolen);
BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
#ifndef HANDLE_FLAG_INHERIT
#define HANDLE_FLAG_INHERIT 1
#endif
HANDLE winsock_lib;
static int winsock_inuse;
BOOL
term_winsock (void)
{
if (winsock_lib != NULL && winsock_inuse == 0)
{
if (pfn_WSACleanup () == 0 ||
pfn_WSAGetLastError () == WSAENETDOWN)
{
if (FreeLibrary (winsock_lib))
winsock_lib = NULL;
return TRUE;
}
}
return FALSE;
}
BOOL
init_winsock (int load_now)
{
WSADATA winsockData;
if (winsock_lib != NULL)
return TRUE;
pfn_SetHandleInformation = NULL;
pfn_SetHandleInformation
= (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
"SetHandleInformation");
winsock_lib = LoadLibrary ("Ws2_32.dll");
if (winsock_lib != NULL)
{
#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( WSAEventSelect );
LOAD_PROC( WSACreateEvent );
LOAD_PROC( WSACloseEvent );
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( getpeername );
LOAD_PROC( WSACleanup );
LOAD_PROC( setsockopt );
LOAD_PROC( listen );
LOAD_PROC( getsockname );
LOAD_PROC( accept );
LOAD_PROC( recvfrom );
LOAD_PROC( sendto );
#undef LOAD_PROC
if (pfn_WSAStartup (0x101, &winsockData) == 0)
{
if (winsockData.wVersion != 0x101)
goto fail;
if (!load_now)
{
pfn_WSACleanup ();
FreeLibrary (winsock_lib);
winsock_lib = NULL;
}
winsock_inuse = 0;
return TRUE;
}
fail:
FreeLibrary (winsock_lib);
winsock_lib = NULL;
}
return FALSE;
}
int h_errno = 0;
static void
set_errno ()
{
if (winsock_lib == NULL)
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 && winsock_lib != NULL)
pfn_WSASetLastError (0);
}
struct {
int errnum;
char * msg;
} _wsa_errlist[] = {
WSAEINTR , "Interrupted function call",
WSAEBADF , "Bad file descriptor",
WSAEACCES , "Permission denied",
WSAEFAULT , "Bad address",
WSAEINVAL , "Invalid argument",
WSAEMFILE , "Too many open files",
WSAEWOULDBLOCK , "Resource temporarily unavailable",
WSAEINPROGRESS , "Operation now in progress",
WSAEALREADY , "Operation already in progress",
WSAENOTSOCK , "Socket operation on non-socket",
WSAEDESTADDRREQ , "Destination address required",
WSAEMSGSIZE , "Message too long",
WSAEPROTOTYPE , "Protocol wrong type for socket",
WSAENOPROTOOPT , "Bad protocol option",
WSAEPROTONOSUPPORT , "Protocol not supported",
WSAESOCKTNOSUPPORT , "Socket type not supported",
WSAEOPNOTSUPP , "Operation not supported",
WSAEPFNOSUPPORT , "Protocol family not supported",
WSAEAFNOSUPPORT , "Address family not supported by protocol family",
WSAEADDRINUSE , "Address already in use",
WSAEADDRNOTAVAIL , "Cannot assign requested address",
WSAENETDOWN , "Network is down",
WSAENETUNREACH , "Network is unreachable",
WSAENETRESET , "Network dropped connection on reset",
WSAECONNABORTED , "Software caused connection abort",
WSAECONNRESET , "Connection reset by peer",
WSAENOBUFS , "No buffer space available",
WSAEISCONN , "Socket is already connected",
WSAENOTCONN , "Socket is not connected",
WSAESHUTDOWN , "Cannot send after socket shutdown",
WSAETOOMANYREFS , "Too many references",
WSAETIMEDOUT , "Connection timed out",
WSAECONNREFUSED , "Connection refused",
WSAELOOP , "Network loop",
WSAENAMETOOLONG , "Name is too long",
WSAEHOSTDOWN , "Host is down",
WSAEHOSTUNREACH , "No route to host",
WSAENOTEMPTY , "Buffer not empty",
WSAEPROCLIM , "Too many processes",
WSAEUSERS , "Too many users",
WSAEDQUOT , "Double quote in host name",
WSAESTALE , "Data is stale",
WSAEREMOTE , "Remote error",
WSASYSNOTREADY , "Network subsystem is unavailable",
WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
WSANOTINITIALISED , "Winsock not initialized successfully",
WSAEDISCON , "Graceful shutdown in progress",
#ifdef WSAENOMORE
WSAENOMORE , "No more operations allowed",
WSAECANCELLED , "Operation cancelled",
WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
WSAEINVALIDPROVIDER , "Invalid service provider version number",
WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
WSASYSCALLFAILURE , "System call failured",
WSASERVICE_NOT_FOUND , "Service not found",
WSATYPE_NOT_FOUND , "Class type not found",
WSA_E_NO_MORE , "No more resources available",
WSA_E_CANCELLED , "Operation already cancelled",
WSAEREFUSED , "Operation refused",
#endif
WSAHOST_NOT_FOUND , "Host not found",
WSATRY_AGAIN , "Authoritative host not found during name lookup",
WSANO_RECOVERY , "Non-recoverable error during name lookup",
WSANO_DATA , "Valid name, no data record of requested type",
-1, NULL
};
char *
sys_strerror(int error_no)
{
int i;
static char unknown_msg[40];
if (error_no >= 0 && error_no < sys_nerr)
return sys_errlist[error_no];
for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
if (_wsa_errlist[i].errnum == error_no)
return _wsa_errlist[i].msg;
sprintf(unknown_msg, "Unidentified error: %d", error_no);
return unknown_msg;
}
#ifdef SOCK_REPLACE_HANDLE
#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
#else
#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
#endif
int socket_to_fd (SOCKET s);
int
sys_socket(int af, int type, int protocol)
{
SOCKET s;
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return INVALID_SOCKET;
}
check_errno ();
s = pfn_socket (af, type, protocol);
if (s != INVALID_SOCKET)
return socket_to_fd (s);
set_errno ();
return -1;
}
int
socket_to_fd (SOCKET s)
{
int fd;
child_process * cp;
fd = _open ("NUL:", _O_RDWR);
if (fd >= 0)
{
#ifdef SOCK_REPLACE_HANDLE
CloseHandle ((HANDLE) _get_osfhandle (fd));
_free_osfhnd (fd);
_set_osfhnd (fd, s);
#else
{
if (pfn_SetHandleInformation)
{
pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
}
else
{
HANDLE parent = GetCurrentProcess ();
HANDLE new_s = INVALID_HANDLE_VALUE;
if (DuplicateHandle (parent,
(HANDLE) s,
parent,
&new_s,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
long nonblocking = 0;
if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
{
pfn_closesocket (s);
s = (SOCKET) new_s;
}
else
{
CloseHandle (new_s);
}
}
}
}
fd_info[fd].hnd = (HANDLE) s;
#endif
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;
if (fd_info[ fd ].cp != NULL)
{
DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
abort ();
}
fd_info[ fd ].cp = cp;
winsock_inuse++;
return fd;
}
_close (fd);
}
pfn_closesocket (s);
h_errno = EMFILE;
return -1;
}
int
sys_bind (int s, const struct sockaddr * addr, int namelen)
{
if (winsock_lib == NULL)
{
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 (winsock_lib == NULL)
{
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 (winsock_lib != NULL) ?
pfn_htons (hostshort) : hostshort;
}
u_short
sys_ntohs (u_short netshort)
{
return (winsock_lib != NULL) ?
pfn_ntohs (netshort) : netshort;
}
unsigned long
sys_inet_addr (const char * cp)
{
return (winsock_lib != NULL) ?
pfn_inet_addr (cp) : INADDR_NONE;
}
int
sys_gethostname (char * name, int namelen)
{
if (winsock_lib != NULL)
return pfn_gethostname (name, namelen);
if (namelen > MAX_COMPUTERNAME_LENGTH)
return !GetComputerName (name, (DWORD *)&namelen);
h_errno = EFAULT;
return SOCKET_ERROR;
}
struct hostent *
sys_gethostbyname(const char * name)
{
struct hostent * host;
if (winsock_lib == NULL)
{
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 (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return NULL;
}
check_errno ();
serv = pfn_getservbyname (name, proto);
if (!serv)
set_errno ();
return serv;
}
int
sys_getpeername (int s, struct sockaddr *addr, int * namelen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_shutdown (int s, int how)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_shutdown (SOCK_HANDLE (s), how);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
(const char *)optval, optlen);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_listen (int s, int backlog)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_listen (SOCK_HANDLE (s), backlog);
if (rc == SOCKET_ERROR)
set_errno ();
else
fd_info[s].flags |= FILE_LISTEN;
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_getsockname (int s, struct sockaddr * name, int * namelen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_accept (int s, struct sockaddr * addr, int * addrlen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return -1;
}
check_errno ();
if (fd_info[s].flags & FILE_LISTEN)
{
SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
int fd = -1;
if (t == INVALID_SOCKET)
set_errno ();
else
fd = socket_to_fd (t);
fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
ResetEvent (fd_info[s].cp->char_avail);
return fd;
}
h_errno = ENOTSOCK;
return -1;
}
int
sys_recvfrom (int s, char * buf, int len, int flags,
struct sockaddr * from, int * fromlen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
sys_sendto (int s, const char * buf, int len, int flags,
const struct sockaddr * to, int tolen)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return SOCKET_ERROR;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
if (rc == SOCKET_ERROR)
set_errno ();
return rc;
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
int
fcntl (int s, int cmd, int options)
{
if (winsock_lib == NULL)
{
h_errno = ENETDOWN;
return -1;
}
check_errno ();
if (fd_info[s].flags & FILE_SOCKET)
{
if (cmd == F_SETFL && options == O_NDELAY)
{
unsigned long nblock = 1;
int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
if (rc == SOCKET_ERROR)
set_errno();
fd_info[s].flags |= FILE_NDELAY;
return rc;
}
else
{
h_errno = EINVAL;
return SOCKET_ERROR;
}
}
h_errno = ENOTSOCK;
return SOCKET_ERROR;
}
#endif
int
sys_close (int fd)
{
int rc;
if (fd < 0)
{
errno = EBADF;
return -1;
}
if (fd < MAXDESC && fd_info[fd].cp)
{
child_process * cp = fd_info[fd].cp;
fd_info[fd].cp = NULL;
if (CHILD_ACTIVE (cp))
{
int i;
for (i = 0; i < MAXDESC; i++)
{
if (i == fd)
continue;
if (fd_info[i].cp == cp)
break;
}
if (i == MAXDESC)
{
#ifdef HAVE_SOCKETS
if (fd_info[fd].flags & FILE_SOCKET)
{
#ifndef SOCK_REPLACE_HANDLE
if (winsock_lib == NULL) abort ();
pfn_shutdown (SOCK_HANDLE (fd), 2);
rc = pfn_closesocket (SOCK_HANDLE (fd));
#endif
winsock_inuse--;
}
#endif
delete_child (cp);
}
}
}
rc = _close (fd);
if (rc == 0 && fd < MAXDESC)
fd_info[fd].flags = 0;
return rc;
}
int
sys_dup (int fd)
{
int new_fd;
new_fd = _dup (fd);
if (new_fd >= 0 && new_fd < MAXDESC)
{
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;
}
if (src != dst && fd_info[dst].flags != 0)
sys_close (dst);
rc = _dup2 (src, dst);
if (rc == 0)
{
fd_info[dst] = fd_info[src];
}
return rc;
}
int
sys_pipe (int * phandles)
{
int rc;
unsigned flags;
rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
if (rc == 0)
{
if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
{
_close (phandles[0]);
_close (phandles[1]);
rc = -1;
}
else
{
flags = FILE_PIPE | FILE_READ | FILE_BINARY;
fd_info[phandles[0]].flags = flags;
flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
fd_info[phandles[1]].flags = flags;
}
}
return rc;
}
extern int w32_pipe_read_delay;
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)
{
rc = _read (fd, &cp->chr, sizeof (char));
if (rc > 0)
{
int wait = w32_pipe_read_delay;
if (wait > 0)
Sleep (wait);
else if (wait < 0)
while (++wait <= 0)
Sleep (0);
}
}
#ifdef HAVE_SOCKETS
else if (fd_info[fd].flags & FILE_SOCKET)
{
unsigned long nblock = 0;
if (fd_info[fd].flags & FILE_NDELAY)
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
if (fd_info[fd].flags & FILE_NDELAY)
{
nblock = 1;
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
}
}
#endif
if (rc == sizeof (char))
cp->status = STATUS_READ_SUCCEEDED;
else
cp->status = STATUS_READ_FAILED;
return cp->status;
}
int
_sys_wait_accept (int fd)
{
HANDLE hEv;
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;
cp->status = STATUS_READ_FAILED;
hEv = pfn_WSACreateEvent ();
rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
if (rc != SOCKET_ERROR)
{
rc = WaitForSingleObject (hEv, INFINITE);
pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
if (rc == WAIT_OBJECT_0)
cp->status = STATUS_READ_SUCCEEDED;
}
pfn_WSACloseEvent (hEv);
return cp->status;
}
int
sys_read (int fd, char * buffer, unsigned int count)
{
int nchars;
int to_read;
DWORD waiting;
char * orig_buffer = buffer;
if (fd < 0)
{
errno = EBADF;
return -1;
}
if (fd < MAXDESC && 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;
}
nchars = 0;
if (fd_info[fd].flags & FILE_LAST_CR)
{
if (fd_info[fd].flags & FILE_BINARY) abort ();
*buffer++ = 0x0d;
count--;
nchars++;
fd_info[fd].flags &= ~FILE_LAST_CR;
}
if (cp)
{
int current_status = cp->status;
switch (current_status)
{
case STATUS_READ_FAILED:
case STATUS_READ_ERROR:
if (nchars <= 0)
fd_info[fd].flags |= FILE_AT_EOF;
return nchars;
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:
*buffer++ = cp->chr;
count--;
nchars++;
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);
if (to_read > 0)
nchars += _read (fd, buffer, to_read);
}
#ifdef HAVE_SOCKETS
else
{
if (winsock_lib == NULL) abort ();
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
if (waiting == 0 && nchars == 0)
{
h_errno = errno = EWOULDBLOCK;
return -1;
}
if (waiting)
{
int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
if (res == SOCKET_ERROR)
{
DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
set_errno ();
return -1;
}
nchars += res;
}
}
#endif
}
else
{
int nread = _read (fd, buffer, count);
if (nread >= 0)
nchars += nread;
else if (nchars == 0)
nchars = nread;
}
if (nchars <= 0)
fd_info[fd].flags |= FILE_AT_EOF;
else if ((fd_info[fd].flags & FILE_BINARY) == 0)
{
nchars = crlf_to_lf (nchars, orig_buffer);
if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
{
fd_info[fd].flags |= FILE_LAST_CR;
nchars--;
}
}
}
else
nchars = _read (fd, buffer, count);
return nchars;
}
int
sys_write (int fd, const void * buffer, unsigned int count)
{
int nchars;
if (fd < 0)
{
errno = EBADF;
return -1;
}
if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
{
if ((fd_info[fd].flags & FILE_WRITE) == 0)
{
errno = EBADF;
return -1;
}
if ((fd_info[fd].flags & FILE_BINARY) == 0)
{
char * tmpbuf = alloca (count * 2);
unsigned char * src = (void *)buffer;
unsigned char * dst = tmpbuf;
int nbytes = count;
while (1)
{
unsigned char *next;
next = _memccpy (dst, src, '\n', nbytes);
if (next)
{
int copied = next - dst;
nbytes -= copied;
src += copied;
next[-1] = '\r';
next[0] = '\n';
dst = next + 1;
count++;
}
else
break;
}
buffer = tmpbuf;
}
}
#ifdef HAVE_SOCKETS
if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
{
unsigned long nblock = 0;
if (winsock_lib == NULL) abort ();
if (fd_info[fd].flags & FILE_NDELAY)
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
if (fd_info[fd].flags & FILE_NDELAY)
{
nblock = 1;
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
}
if (nchars == SOCKET_ERROR)
{
DebPrint(("sys_write.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;
}
static void
check_windows_init_file ()
{
extern int noninteractive, inhibit_window_system;
if (!noninteractive && !inhibit_window_system)
{
extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
Lisp_Object objs[2];
Lisp_Object full_load_path;
Lisp_Object init_file;
int fd;
objs[0] = Vload_path;
objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
full_load_path = Fappend (2, objs);
init_file = build_string ("term/w32-win");
fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
if (fd < 0)
{
Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
char *init_file_name = SDATA (init_file);
char *load_path = SDATA (load_path_print);
char *buffer = alloca (1024
+ strlen (init_file_name)
+ strlen (load_path));
sprintf (buffer,
"The Emacs Windows initialization file \"%s.el\" "
"could not be found in your Emacs installation. "
"Emacs checked the following directories for this file:\n"
"\n%s\n\n"
"When Emacs cannot find this file, it usually means that it "
"was not installed properly, or its distribution file was "
"not unpacked properly.\nSee the README.W32 file in the "
"top-level Emacs directory for more information.",
init_file_name, load_path);
MessageBox (NULL,
buffer,
"Emacs Abort Dialog",
MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
#undef abort
abort ();
}
else
{
_close (fd);
}
}
}
void
term_ntproc ()
{
#ifdef HAVE_SOCKETS
term_winsock ();
#endif
term_w32select ();
}
void
init_ntproc ()
{
#ifdef HAVE_SOCKETS
winsock_lib = NULL;
if (getenv ("PRELOAD_WINSOCK") != NULL)
init_winsock (TRUE);
#endif
{
HANDLE parent;
HANDLE stdin_save = INVALID_HANDLE_VALUE;
HANDLE stdout_save = INVALID_HANDLE_VALUE;
HANDLE stderr_save = INVALID_HANDLE_VALUE;
parent = GetCurrentProcess ();
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");
}
signal (SIGABRT, term_ntproc);
{
char drive[] = "A:\\";
while (*drive <= 'Z')
{
fixed_drives[DRIVE_INDEX (*drive)] =
(GetDriveType (drive) == DRIVE_FIXED);
(*drive)++;
}
volume_cache = NULL;
}
check_windows_init_file ();
}
BOOL WINAPI shutdown_handler(DWORD type)
{
if (type == CTRL_CLOSE_EVENT
|| type == CTRL_LOGOFF_EVENT
|| type == CTRL_SHUTDOWN_EVENT)
{
shut_down_emacs (0, 0, Qnil);
}
return FALSE;
}
void
globals_of_w32 ()
{
g_b_init_is_windows_9x = 0;
g_b_init_open_process_token = 0;
g_b_init_get_token_information = 0;
g_b_init_lookup_account_sid = 0;
g_b_init_get_sid_identifier_authority = 0;
SetConsoleCtrlHandler(shutdown_handler, TRUE);
}