-/* Utility and Unix shadow routines for XEmacs on Windows NT.
+/* Utility and Unix shadow routines for XEmacs on MS Windows.
Copyright (C) 1994, 1995 Free Software Foundation, Inc.
This file is part of XEmacs.
#define getwd _getwd
#include "lisp.h"
#undef getwd
+#include "buffer.h"
#include "systime.h"
#include "syssignal.h"
#endif
extern Lisp_Object Vmswindows_get_true_file_attributes;
-int nt_fake_unix_uid;
+Fixnum nt_fake_unix_uid;
static char startup_dir[ MAXPATHLEN ];
if (getenv ("HOME") == NULL)
putenv ("HOME=c:/");
#endif
- if (getenv ("SHELL") == NULL)
- putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
- /* Set dir and shell from environment variables. */
+ /* Set dir from environment variables. */
strcpy (the_passwd.pw_dir, (char *)get_home_directory());
- strcpy (the_passwd.pw_shell, getenv ("SHELL"));
+ /* We used to set pw_shell here, but the order is wrong (SHELL gets
+ init in callproc.c, called later in the init process) and pw_shell
+ is not used anywhere. */
}
/* Normalize filename by converting all path separators to
}
#endif /* 0 */
-#define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
+#define REG_ROOT "SOFTWARE\\XEmacs\\XEmacs"
LPBYTE
nt_get_resource (char *key, LPDWORD lpdwtype)
renaming or deleting directories. (We also don't call chdir when
running subprocesses for the same reason.) */
if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
- abort ();
+ ABORT ();
{
char *p;
char modname[MAX_PATH];
if (!GetModuleFileName (NULL, modname, MAX_PATH))
- abort ();
+ ABORT ();
if ((p = strrchr (modname, '\\')) == NULL)
- abort ();
+ ABORT ();
*p = 0;
SetCurrentDirectory (modname);
#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)
{
}
#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
doesn't resolve aliasing due to subst commands, or recognize hard
links. */
if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
- abort ();
+ ABORT ();
parse_root (fullname, &p);
/* Normal Win32 filesystems are still case insensitive. */
a compatibility test. --kkm */
/* Since stat is encapsulated on Windows NT, we need to encapsulate
- the equally broken fstat as well. */
+ the equally broken fstat as well. FSFmacs also provides its own
+ utime. Is that necessary here too? */
int
-mswindows_fstat (int handle, struct stat *buffer)
+mswindows_fstat (int desc, struct stat * buf)
{
- int ret;
- BY_HANDLE_FILE_INFORMATION lpFileInfo;
- /* Initialize values */
- buffer->st_mode = 0;
- buffer->st_size = 0;
- buffer->st_dev = 0;
- buffer->st_rdev = 0;
- buffer->st_atime = 0;
- buffer->st_ctime = 0;
- buffer->st_mtime = 0;
- buffer->st_nlink = 0;
- ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
- if (!ret)
+ HANDLE fh = (HANDLE) _get_osfhandle (desc);
+ BY_HANDLE_FILE_INFORMATION info;
+ DWORD fake_inode;
+ int permission;
+
+ switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
{
- return -1;
+ 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 = 2; /* doesn't really matter */
+ fake_inode = 0; /* this doesn't either I think */
}
else
{
- buffer->st_mtime = convert_time (lpFileInfo.ftLastWriteTime);
- buffer->st_atime = convert_time (lpFileInfo.ftLastAccessTime);
- if (buffer->st_atime == 0) buffer->st_atime = buffer->st_mtime;
- buffer->st_ctime = convert_time (lpFileInfo.ftCreationTime);
- if (buffer->st_ctime == 0) buffer->st_ctime = buffer->st_mtime;
- buffer->st_size = lpFileInfo.nFileSizeLow;
- buffer->st_nlink = (short) lpFileInfo.nNumberOfLinks;
- return 0;
+ buf->st_nlink = (short) info.nNumberOfLinks;
+ /* Might as well use file index to fake inode values, but this
+ is not guaranteed to be unique unless we keep a handle open
+ all the time (even then there are situations where it is
+ not unique). Reputedly, there are at most 48 bits of info
+ (on NTFS, presumably less on FAT). */
+ fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
}
+
+ /* MSVC defines _ino_t to be short; other libc's might not. */
+ if (sizeof (buf->st_ino) == 2)
+ buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
+ else
+ buf->st_ino = (unsigned short) fake_inode;
+
+ /* consider files to belong to current user */
+ buf->st_uid = 0;
+ buf->st_gid = 0;
+
+ buf->st_dev = info.dwVolumeSerialNumber;
+ buf->st_rdev = info.dwVolumeSerialNumber;
+
+ buf->st_size = info.nFileSizeLow;
+
+ /* Convert timestamps to Unix format. */
+ 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;
+
+ /* determine rwx permissions */
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ permission = _S_IREAD | _S_IEXEC;
+ else
+ permission = _S_IREAD | _S_IEXEC |_S_IWRITE;
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ permission |= _S_IEXEC;
+
+ buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
+
+ return 0;
}
/* MSVC stat function can't cope with UNC names and has other bugs, so
int permission;
int len;
int rootdir = FALSE;
+ int errm;
if (path == NULL || buf == NULL)
{
rootdir = (path >= name + len - 1
&& (IS_DIRECTORY_SEP (*path) || *path == 0));
name = strcpy ((char *)alloca (len + 2), name);
-
+ errm = SetErrorMode (SEM_FAILCRITICALERRORS
+ | SEM_NOOPENFILEERRORBOX);
if (rootdir)
{
if (!IS_DIRECTORY_SEP (name[len-1]))
strcat (name, "\\");
+
if (GetDriveType (name) < 2)
{
+ SetErrorMode (errm);
errno = ENOENT;
return -1;
}
}
else
{
- fh = FindFirstFile (name, &wfd);
- if (fh == INVALID_HANDLE_VALUE)
- {
- errno = ENOENT;
- return -1;
+ fh = FindFirstFile (name, &wfd);
+ if (fh == INVALID_HANDLE_VALUE)
+ {
+ SetErrorMode (errm);
+ errno = ENOENT;
+ return -1;
+ }
+ FindClose (fh);
}
- FindClose (fh);
- }
}
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
}
else
{
+ SetErrorMode (errm);
errno = EACCES;
return -1;
}
fake_inode = 0;
}
+ SetErrorMode (errm);
+
#if 0
/* Not sure if there is any point in this. */
if (!NILP (Vwin32_generate_fake_inodes))
buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
/* consider files to belong to current user */
- buf->st_uid = buf->st_gid = nt_fake_unix_uid;
+ buf->st_uid = buf->st_gid = (short) nt_fake_unix_uid;
/* volume_info is set indirectly by map_win32_filename */
buf->st_dev = volume_info.serialnum;
/* determine rwx permissions */
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- permission = _S_IREAD;
+ permission = _S_IREAD | _S_IEXEC;
else
- permission = _S_IREAD | _S_IWRITE;
+ permission = _S_IREAD | _S_IEXEC |_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);
/* Signal pending mask: bit set to 1 means sig is pending */
unsigned signal_pending_mask = 0;
-mswindows_sighandler mswindows_sigset (int nsig, mswindows_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)
}
}
-int mswindows_sighold (int nsig)
+int
+mswindows_sighold (int nsig)
{
if (nsig < 0 || nsig > SIG_MAX)
return errno = EINVAL;
- signal_block_mask |= sigmask(nsig);
+ signal_block_mask |= sigmask (nsig);
return 0;
}
-int mswindows_sigrelse (int nsig)
+int
+mswindows_sigrelse (int nsig)
{
if (nsig < 0 || nsig > SIG_MAX)
return errno = EINVAL;
- signal_block_mask &= ~sigmask(nsig);
+ signal_block_mask &= ~sigmask (nsig);
- if (signal_pending_mask & sigmask(nsig))
+ if (signal_pending_mask & sigmask (nsig))
mswindows_raise (nsig);
return 0;
}
-int mswindows_sigpause (int nsig)
+int
+mswindows_sigpause (int nsig)
{
- /* This is currently not called, because the only
- call to sigpause inside XEmacs is with SIGCHLD
- parameter. Just in case, we put an assert here,
- so anyone who will add a call to sigpause will
- be surprised (or surprise someone else...) */
+ /* This is currently not called, because the only call to sigpause
+ inside XEmacs is with SIGCHLD parameter. Just in case, we put an
+ assert here, so anyone adds a call to sigpause will be surprised
+ (or surprise someone else...) */
assert (0);
return 0;
}
-int mswindows_raise (int nsig)
+int
+mswindows_raise (int nsig)
{
/* We delegate some raises to the system routine */
if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
return errno = EINVAL;
/* If the signal is blocked, remember to issue later */
- if (signal_block_mask & sigmask(nsig))
+ if (signal_block_mask & sigmask (nsig))
{
- signal_pending_mask |= sigmask(nsig);
+ signal_pending_mask |= sigmask (nsig);
return 0;
}
if (signal_handlers[nsig] != SIG_DFL)
{
- (*signal_handlers[nsig])(nsig);
+ (*signal_handlers[nsig]) (nsig);
return 0;
}
return 0;
}
-/*--------------------------------------------------------------------*/
-/* Async timers */
-/*--------------------------------------------------------------------*/
-
-/* We emulate two timers, one for SIGALRM, another for SIGPROF.
-
- itimerproc() function has an implementation limitation: it does
- not allow to set *both* interval and period. If an attempt is
- made to set both, and then they are unequal, the function
- asserts.
-
- Minimum timer resolution on Win32 systems varies, and is greater
- than or equal than 1 ms. The resolution is always wrapped not to
- attempt to get below the system defined limit.
- */
-
-/* Timer precision, denominator of one fraction: for 100 ms
- interval, request 10 ms precision
- */
-const int timer_prec = 10;
-
-/* Last itimervals, as set by calls to setitimer */
-static struct itimerval it_alarm;
-static struct itimerval it_prof;
-
-/* Timer IDs as returned by MM */
-MMRESULT tid_alarm = 0;
-MMRESULT tid_prof = 0;
-
-static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
- DWORD dw1, DWORD dw2)
-{
- /* Just raise a signal indicated by dwUser parameter */
- mswindows_raise (dwUser);
-}
-
-/* Divide time in ms specified by IT by DENOM. Return 1 ms
- if division results in zero */
-static UINT period (const struct itimerval* it, UINT denom)
-{
- static TIMECAPS time_caps;
-
- UINT res;
- const struct timeval* tv =
- (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
- ? &it->it_interval : &it->it_value;
-
- /* Zero means stop timer */
- if (tv->tv_sec == 0 && tv->tv_usec == 0)
- return 0;
-
- /* Convert to ms and divide by denom */
- res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
-
- /* Converge to minimum timer resolution */
- if (time_caps.wPeriodMin == 0)
- timeGetDevCaps (&time_caps, sizeof(time_caps));
-
- if (res < time_caps.wPeriodMin)
- res = time_caps.wPeriodMin;
-
- return res;
-}
-
-static int setitimer_helper (const struct itimerval* itnew,
- struct itimerval* itold, struct itimerval* itcurrent,
- MMRESULT* tid, DWORD sigkind)
-{
- UINT delay, resolution, event_type;
-
- /* First stop the old timer */
- if (*tid)
- {
- timeKillEvent (*tid);
- timeEndPeriod (period (itcurrent, timer_prec));
- *tid = 0;
- }
-
- /* Return old itimerval if requested */
- if (itold)
- *itold = *itcurrent;
-
- *itcurrent = *itnew;
-
- /* Determine if to start new timer */
- delay = period (itnew, 1);
- if (delay)
- {
- resolution = period (itnew, timer_prec);
- event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
- ? TIME_ONESHOT : TIME_PERIODIC;
- timeBeginPeriod (resolution);
- *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
- }
-
- return !delay || *tid;
-}
-
-int setitimer (int kind, const struct itimerval* itnew,
- struct itimerval* itold)
-{
- /* In this version, both interval and value are allowed
- only if they are equal. */
- assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
- || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
- || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
- itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
-
- if (kind == ITIMER_REAL)
- return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
- else if (kind == ITIMER_PROF)
- return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
- else
- return errno = EINVAL;
-}
-
\f
/*--------------------------------------------------------------------*/
/* Memory-mapped files */
close_file_data (&executable);
}
+static 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 - (4096.0 * 1024 * 1024) *
+ pft->dwHighDateTime);
+}
+
+int
+mswindows_utime (Lisp_Object path, struct utimbuf *times)
+{
+ struct utimbuf deftime;
+#if 0
+ HANDLE fh;
+#endif
+ static FILETIME mtime;
+ static FILETIME atime;
+ Extbyte *filename;
+
+ if (times == NULL)
+ {
+ deftime.modtime = deftime.actime = time (NULL);
+ times = &deftime;
+ }
+
+ LISP_STRING_TO_EXTERNAL (path, filename, Qmswindows_tstr);
+ /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */
+#if 0
+ /* Need write access to set times. */
+ fh = CreateFile (filename, 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;
+#else
+ return utime (filename, times);
+#endif
+}
+
/* Close the system structures associated with the given file. */
void
close_file_data (file_data *p_file)
{
- UnmapViewOfFile (p_file->file_base);
- CloseHandle (p_file->file_mapping);
- CloseHandle (p_file->file);
+ UnmapViewOfFile (p_file->file_base);
+ CloseHandle (p_file->file_mapping);
+ CloseHandle (p_file->file);
}
void