/* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
#include <config.h>
-
-#undef signal
#define getwd _getwd
#include "lisp.h"
#undef getwd
#include "syssignal.h"
#include "sysproc.h"
#include "sysfile.h"
+#include "syspwd.h"
+#include "sysdir.h"
-#include <ctype.h>
-#include <direct.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <io.h>
-#include <pwd.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <windows.h>
-#ifndef __MINGW32__
-#include <mmsystem.h>
-#else
-typedef void (CALLBACK TIMECALLBACK)(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
-
-typedef TIMECALLBACK FAR *LPTIMECALLBACK;
-DWORD WINAPI timeGetTime(void);
-MMRESULT WINAPI timeSetEvent(UINT uDelay, UINT uResolution,
- LPTIMECALLBACK fptc, DWORD dwUser, UINT fuEvent);
-MMRESULT WINAPI timeKillEvent(UINT uTimerID);
-MMRESULT WINAPI timeGetDevCaps(TIMECAPS* ptc, UINT cbtc);
-MMRESULT WINAPI timeBeginPeriod(UINT uPeriod);
-MMRESULT WINAPI timeEndPeriod(UINT uPeriod);
-#endif
+#include "syswindows.h"
#include "nt.h"
-#include <sys/dir.h>
#include "ntheap.h"
#endif
extern Lisp_Object Vmswindows_get_true_file_attributes;
-extern char *get_home_directory(void);
+int nt_fake_unix_uid;
static char startup_dir[ MAXPATHLEN ];
#endif
}
-/* 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 getpwuid, getpwnam and others. */
#define PASSWD_FIELD_SIZE 256
};
uid_t
-getuid ()
-{
- return the_passwd.pw_uid;
+getuid (void)
+{
+ return nt_fake_unix_uid;
}
uid_t
-geteuid ()
+geteuid (void)
{
- /* 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 ();
+ return nt_fake_unix_uid;
}
gid_t
-getgid ()
+getgid (void)
{
return the_passwd.pw_gid;
}
gid_t
-getegid ()
+getegid (void)
{
return getgid ();
}
struct passwd *
getpwuid (uid_t uid)
{
- if (uid == the_passwd.pw_uid)
- return &the_passwd;
- return NULL;
+ if (uid == nt_fake_unix_uid)
+ {
+ the_passwd.pw_gid = the_passwd.pw_uid = uid;
+ return &the_passwd;
+ }
+ else
+ return NULL;
}
struct passwd *
}
void
-init_user_info ()
+init_user_info (void)
{
+ /* This code is pretty much of ad hoc nature. There is no unix-like
+ UIDs under Windows NT. There is no concept of root user, because
+ all security is ACL-based. Instead, let's use a simple variable,
+ nt-fake-unix-uid, which would allow the user to have a uid of
+ choice. --kkm, 02/03/2000 */
+#if 0
/* Find the user's real name by opening the process token and
looking up the name associated with the user-sid in that token.
the_passwd.pw_gid = 123;
}
+ if (token)
+ CloseHandle (token);
+#else
+ /* Obtain only logon id here, uid part is moved to getuid */
+ char name[256];
+ DWORD length = sizeof (name);
+ if (GetUserName (name, &length))
+ strcpy (the_passwd.pw_name, name);
+ else
+ strcpy (the_passwd.pw_name, "unknown");
+#endif
+
/* Ensure HOME and SHELL are defined. */
#if 0
/*
putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
/* Set dir and shell from environment variables. */
- strcpy (the_passwd.pw_dir, get_home_directory());
+ strcpy (the_passwd.pw_dir, (char *)get_home_directory());
strcpy (the_passwd.pw_shell, getenv ("SHELL"));
-
- if (token)
- CloseHandle (token);
}
/* Normalize filename by converting all path separators to
case path name components to lower case. */
static void
-normalize_filename (fp, path_sep)
- REGISTER char *fp;
- char path_sep;
+normalize_filename (char *fp, char path_sep)
{
char sep;
char *elem;
/* Destructively turn backslashes into slashes. */
void
-dostounix_filename (p)
- REGISTER char *p;
+dostounix_filename (char *p)
{
normalize_filename (p, '/');
}
/* Destructively turn slashes into backslashes. */
void
-unixtodos_filename (p)
- REGISTER char *p;
+unixtodos_filename (char *p)
{
normalize_filename (p, '\\');
}
(From msdos.c...probably should figure out a way to share it,
although this code isn't going to ever change.) */
int
-crlf_to_lf (n, buf, lf_count)
- REGISTER int n;
- REGISTER unsigned char *buf;
- REGISTER unsigned *lf_count;
+crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
{
unsigned char *np = buf;
unsigned char *startp = buf;
#define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
LPBYTE
-nt_get_resource (key, lpdwtype)
- char *key;
- LPDWORD lpdwtype;
+nt_get_resource (char *key, LPDWORD lpdwtype)
{
LPBYTE lpvalue;
HKEY hrootkey = NULL;
}
void
-init_environment ()
+init_environment (void)
{
/* Check for environment variables and use registry if they don't exist */
{
"EMACSLOCKDIR",
"INFOPATH"
};
-#ifdef HEAP_IN_DATA
+#if defined (HEAP_IN_DATA) && !defined(PDUMP)
cache_system_info ();
#endif
for (i = 0; i < countof (env_vars); i++)
return dirp;
}
-void
+int
closedir (DIR *dirp)
{
+ BOOL retval;
+
/* If we have a find-handle open, close it. */
if (dir_find_handle != INVALID_HANDLE_VALUE)
{
- FindClose (dir_find_handle);
+ retval = FindClose (dir_find_handle);
dir_find_handle = INVALID_HANDLE_VALUE;
}
xfree (dirp);
+ if (retval)
+ return 0;
+ else
+ return -1;
}
struct direct *
}
/* Emacs never uses this value, so don't bother making it match
- value returned by stat(). */
+ value returned by xemacs_stat(). */
dir_static.d_ino = 1;
dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
#endif /* 0 */
static FILETIME utc_base_ft;
-static long double utc_base;
static int init = 0;
+#if 0
+
+static long double utc_base;
+
time_t
convert_time (FILETIME ft)
{
ret -= utc_base;
return (time_t) (ret * 1e-7);
}
+#else
+
+#if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
+#define LowPart u.LowPart
+#define HighPart u.HighPart
+#endif
+
+static LARGE_INTEGER utc_base_li;
+
+time_t
+convert_time (FILETIME uft)
+{
+ time_t ret;
+#ifndef MAXLONGLONG
+ SYSTEMTIME st;
+ struct tm t;
+ FILETIME ft;
+ TIME_ZONE_INFORMATION tzi;
+ DWORD tzid;
+#else
+ LARGE_INTEGER lft;
+#endif
+
+ 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_li.LowPart = utc_base_ft.dwLowDateTime;
+ utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
+
+ init = 1;
+ }
+
+#ifdef MAXLONGLONG
+
+ /* On a compiler that supports long integers, do it the easy way */
+ lft.LowPart = uft.dwLowDateTime;
+ lft.HighPart = uft.dwHighDateTime;
+ ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
+
+#else
+
+ /* Do it the hard way using mktime. */
+ FileTimeToLocalFileTime(&uft, &ft);
+ FileTimeToSystemTime (&ft, &st);
+ tzid = GetTimeZoneInformation (&tzi);
+ t.tm_year = st.wYear - 1900;
+ t.tm_mon = st.wMonth - 1;
+ t.tm_mday = st.wDay;
+ t.tm_hour = st.wHour;
+ t.tm_min = st.wMinute;
+ t.tm_sec = st.wSecond;
+ t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
+ /* st.wMilliseconds not applicable */
+ ret = mktime(&t);
+ if (ret == -1)
+ {
+ ret = 0;
+ }
+
+#endif
+
+ return ret;
+}
+#endif
+#if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
+#undef LowPart
+#undef HighPart
+#endif
#if 0
/* in case we ever have need of this */
#endif
+/* #### aichner@ecf.teradyne.com reported that with the library
+ provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
+ (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
+ we opt to use non-encapsulated stat(), this should serve as
+ a compatibility test. --kkm */
+
/* Since stat is encapsulated on Windows NT, we need to encapsulate
the equally broken fstat as well. */
int
-fstat (int handle, struct stat *buffer)
+mswindows_fstat (int handle, struct stat *buffer)
{
int ret;
BY_HANDLE_FILE_INFORMATION lpFileInfo;
buffer->st_ctime = 0;
buffer->st_mtime = 0;
buffer->st_nlink = 0;
- ret = GetFileInformationByHandle((HANDLE) handle, &lpFileInfo);
+ ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
if (!ret)
{
return -1;
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)
+mswindows_stat (const char * path, struct stat * buf)
{
char * name;
WIN32_FIND_DATA wfd;
len = strlen (name);
rootdir = (path >= name + len - 1
&& (IS_DIRECTORY_SEP (*path) || *path == 0));
- name = strcpy (alloca (len + 2), name);
+ name = strcpy ((char *)alloca (len + 2), name);
if (rootdir)
{
buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
/* consider files to belong to current user */
- buf->st_uid = the_passwd.pw_uid;
- buf->st_gid = the_passwd.pw_gid;
+ buf->st_uid = buf->st_gid = nt_fake_unix_uid;
/* volume_info is set indirectly by map_win32_filename */
buf->st_dev = volume_info.serialnum;
buf->st_rdev = volume_info.serialnum;
-
buf->st_size = wfd.nFileSizeLow;
/* Convert timestamps to Unix format. */
}
void
-init_ntproc ()
+init_ntproc (void)
{
/* Initial preparation for subprocess support: replace our standard
handles with non-inheritable versions. */
/* Signal pending mask: bit set to 1 means sig is pending */
unsigned signal_pending_mask = 0;
-msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
+mswindows_sighandler mswindows_sigset (int nsig, mswindows_sighandler handler)
{
/* We delegate some signals to the system function */
if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
/* Store handler ptr */
{
- msw_sighandler old_handler = signal_handlers[nsig];
+ mswindows_sighandler old_handler = signal_handlers[nsig];
signal_handlers[nsig] = handler;
return old_handler;
}
}
-int msw_sighold (int nsig)
+int mswindows_sighold (int nsig)
{
if (nsig < 0 || nsig > SIG_MAX)
return errno = EINVAL;
return 0;
}
-int msw_sigrelse (int nsig)
+int mswindows_sigrelse (int nsig)
{
if (nsig < 0 || nsig > SIG_MAX)
return errno = EINVAL;
signal_block_mask &= ~sigmask(nsig);
if (signal_pending_mask & sigmask(nsig))
- msw_raise (nsig);
+ mswindows_raise (nsig);
return 0;
}
-int msw_sigpause (int nsig)
+int mswindows_sigpause (int nsig)
{
/* This is currently not called, because the only
call to sigpause inside XEmacs is with SIGCHLD
return 0;
}
-int msw_raise (int nsig)
+int mswindows_raise (int nsig)
{
/* We delegate some raises to the system routine */
if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
DWORD dw1, DWORD dw2)
{
/* Just raise a signal indicated by dwUser parameter */
- msw_raise (dwUser);
+ mswindows_raise (dwUser);
}
/* Divide time in ms specified by IT by DENOM. Return 1 ms
return errno = EINVAL;
}
+\f
+/*--------------------------------------------------------------------*/
+/* Memory-mapped files */
+/*--------------------------------------------------------------------*/
+
int
-open_input_file (file_data *p_file, CONST char *filename)
+open_input_file (file_data *p_file, const char *filename)
{
+ /* Synched with FSF 20.6. We fixed some warnings. */
HANDLE file;
HANDLE file_mapping;
void *file_base;
if (file_base == 0)
return FALSE;
- p_file->name = (char*)filename;
+ p_file->name = (char *)filename;
+ p_file->size = size;
+ p_file->file = file;
+ p_file->file_mapping = file_mapping;
+ p_file->file_base = (char *)file_base;
+
+ return TRUE;
+}
+
+int
+open_output_file (file_data *p_file, const char *filename, unsigned long size)
+{
+ /* Synched with FSF 20.6. We fixed some warnings. */
+ HANDLE file;
+ HANDLE file_mapping;
+ void *file_base;
+
+ file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (file == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
+ 0, size, NULL);
+ if (!file_mapping)
+ return FALSE;
+
+ file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
+ if (file_base == NULL)
+ return FALSE;
+
+ p_file->name = filename;
p_file->size = size;
p_file->file = file;
p_file->file_mapping = file_mapping;
- p_file->file_base = file_base;
+ p_file->file_base = (char*) file_base;
return TRUE;
}
+#if 1 /* !defined(MINGW) */
+/* Return pointer to section header for section containing the given
+ relative virtual address. */
+static IMAGE_SECTION_HEADER *
+rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
+{
+ /* Synched with FSF 20.6. We added MINGW stuff. */
+ PIMAGE_SECTION_HEADER section;
+ int i;
+
+ section = IMAGE_FIRST_SECTION (nt_header);
+
+ for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+ {
+ /* Some linkers (eg. the NT SDK linker I believe) swapped the
+ meaning of these two values - or rather, they ignored
+ VirtualSize entirely and always set it to zero. This affects
+ some very old exes (eg. gzip dated Dec 1993). Since
+ mswindows_executable_type relies on this function to work reliably,
+ we need to cope with this. */
+ DWORD real_size = max (section->SizeOfRawData,
+ section->Misc.VirtualSize);
+ if (rva >= section->VirtualAddress
+ && rva < section->VirtualAddress + real_size)
+ return section;
+ section++;
+ }
+ return NULL;
+}
+#endif
+
+void
+mswindows_executable_type (const char * filename, int * is_dos_app,
+ int * is_cygnus_app)
+{
+ /* Synched with FSF 20.6. We added MINGW stuff and casts. */
+ file_data executable;
+ char * p;
+
+ /* Default values in case we can't tell for sure. */
+ *is_dos_app = FALSE;
+ *is_cygnus_app = FALSE;
+
+ if (!open_input_file (&executable, filename))
+ return;
+
+ p = strrchr (filename, '.');
+
+ /* We can only identify DOS .com programs from the extension. */
+ if (p && stricmp (p, ".com") == 0)
+ *is_dos_app = TRUE;
+ else if (p && (stricmp (p, ".bat") == 0 ||
+ stricmp (p, ".cmd") == 0))
+ {
+ /* A DOS shell script - it appears that CreateProcess is happy to
+ accept this (somewhat surprisingly); presumably it looks at
+ COMSPEC to determine what executable to actually invoke.
+ Therefore, we have to do the same here as well. */
+ /* Actually, I think it uses the program association for that
+ extension, which is defined in the registry. */
+ p = egetenv ("COMSPEC");
+ if (p)
+ mswindows_executable_type (p, is_dos_app, is_cygnus_app);
+ }
+ else
+ {
+ /* Look for DOS .exe signature - if found, we must also check that
+ it isn't really a 16- or 32-bit Windows exe, since both formats
+ start with a DOS program stub. Note that 16-bit Windows
+ executables use the OS/2 1.x format. */
+
+#if 0 /* defined( MINGW ) */
+ /* mingw32 doesn't have enough headers to detect cygwin
+ apps, just do what we can. */
+ FILHDR * exe_header;
+
+ exe_header = (FILHDR*) executable.file_base;
+ if (exe_header->e_magic != DOSMAGIC)
+ goto unwind;
+
+ if ((char*) exe_header->e_lfanew > (char*) executable.size)
+ {
+ /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
+ *is_dos_app = TRUE;
+ }
+ else if (exe_header->nt_signature != NT_SIGNATURE)
+ {
+ *is_dos_app = TRUE;
+ }
+#else
+ IMAGE_DOS_HEADER * dos_header;
+ IMAGE_NT_HEADERS * nt_header;
+
+ dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
+ if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+ goto unwind;
+
+ nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
+
+ if ((char*) nt_header > (char*) dos_header + executable.size)
+ {
+ /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
+ *is_dos_app = TRUE;
+ }
+ else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
+ LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
+ {
+ *is_dos_app = TRUE;
+ }
+ else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
+ {
+ /* Look for cygwin.dll in DLL import list. */
+ IMAGE_DATA_DIRECTORY import_dir =
+ nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+ IMAGE_IMPORT_DESCRIPTOR * imports;
+ IMAGE_SECTION_HEADER * section;
+
+ section = rva_to_section (import_dir.VirtualAddress, nt_header);
+ imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
+ section, executable);
+
+ for ( ; imports->Name; imports++)
+ {
+ char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
+
+ /* The exact name of the cygwin dll has changed with
+ various releases, but hopefully this will be reasonably
+ future proof. */
+ if (strncmp (dllname, "cygwin", 6) == 0)
+ {
+ *is_cygnus_app = TRUE;
+ break;
+ }
+ }
+ }
+#endif
+ }
+
+ unwind:
+ close_file_data (&executable);
+}
+
/* Close the system structures associated with the given file. */
void
close_file_data (file_data *p_file)
CloseHandle (p_file->file);
}
+void
+vars_of_nt (void)
+{
+ DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
+*Set uid returned by `user-uid' and `user-real-uid'.
+Under NT and 9x, there is no uids, and even no almighty user called root.
+By setting this variable, you can have any uid of choice. Default is 0.
+Changes to this variable take effect immediately.
+*/ );
+ nt_fake_unix_uid = 0;
+}
+
/* end of nt.c */