XEmacs 21.4.4 "Artificial Intelligence".
[chise/xemacs-chise.git.1] / src / nt.c
index bf46ba2..2eac6d0 100644 (file)
--- a/src/nt.c
+++ b/src/nt.c
@@ -25,32 +25,21 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 /* 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 "buffer.h"
 
 #include "systime.h"
 #include "syssignal.h"
 #include "sysproc.h"
 #include "sysfile.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 "syspwd.h"
+#include "sysdir.h"
 
 #include "syswindows.h"
 
 #include "nt.h"
-#include <sys/dir.h>
 #include "ntheap.h"
 
 
@@ -60,7 +49,7 @@ extern Lisp_Object Vwin32_generate_fake_inodes;
 #endif
 extern Lisp_Object Vmswindows_get_true_file_attributes;
 
-int nt_fake_unix_uid;
+Fixnum nt_fake_unix_uid;
 
 static char startup_dir[ MAXPATHLEN ];
 
@@ -81,20 +70,6 @@ getwd (char *dir)
 #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
@@ -1075,16 +1050,22 @@ opendir (const char *filename)
   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 *
@@ -1114,7 +1095,7 @@ readdir (DIR *dirp)
     }
   
   /* 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 +
@@ -1197,12 +1178,11 @@ sys_rename (const char * oldname, const char * newname)
 #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)
 {
@@ -1236,11 +1216,6 @@ convert_time (FILETIME ft)
 }
 #else
 
-#if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
-#define LowPart u.LowPart
-#define HighPart u.HighPart
-#endif
-
 static LARGE_INTEGER utc_base_li;
 
 time_t
@@ -1310,7 +1285,7 @@ convert_time (FILETIME uft)
   return ret;
 }
 #endif
-#if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
+#if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
 #undef LowPart
 #undef HighPart
 #endif
@@ -1391,57 +1366,106 @@ generate_inode_val (const char * name)
 
 #endif
 
-/* stat has been fixed since MSVC 5.0.
-   Oh, and do not encapsulater stat for non-MS compilers, too */
-/* #### popineau@ese-metz.fr says they still might be broken.
-   Oh well... Let's add that `1 ||' condition.... --kkm */
 /* #### 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 */
 
-#if 1 || defined(_MSC_VER) && _MSC_VER < 1100
-
 /* Since stat is encapsulated on Windows NT, we need to encapsulate
-   the equally broken fstat as well. */
-int _cdecl
-fstat (int handle, struct stat *buffer)
+   the equally broken fstat as well. FSFmacs also provides its own
+   utime. Is that necessary here too? */
+int
+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;
+  else
+    permission = _S_IREAD | _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
    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;
@@ -1589,7 +1613,7 @@ stat (const char * path, struct stat * buf)
   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;
@@ -1627,7 +1651,6 @@ stat (const char * path, struct stat * buf)
 
   return 0;
 }
-#endif /* defined(_MSC_VER) && _MSC_VER < 1100 */
 
 /* From callproc.c  */
 extern Lisp_Object Vbinary_process_input;
@@ -1801,7 +1824,7 @@ unsigned signal_block_mask = 0;
 /* 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)
@@ -1815,13 +1838,13 @@ msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
 
   /* 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;
@@ -1830,7 +1853,7 @@ int msw_sighold (int nsig)
   return 0;
 }
 
-int msw_sigrelse (int nsig)
+int mswindows_sigrelse (int nsig)
 {
   if (nsig < 0 || nsig > SIG_MAX)
     return errno = EINVAL;
@@ -1838,12 +1861,12 @@ int msw_sigrelse (int nsig)
   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
@@ -1854,7 +1877,7 @@ int msw_sigpause (int nsig)
   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)
@@ -1920,7 +1943,7 @@ static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
                                 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
@@ -2072,13 +2095,13 @@ open_output_file (file_data *p_file, const char *filename, unsigned long size)
   return TRUE;
 }
 
-#if 1 /* !defined(__MINGW32__) */
+#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 MINGW32 stuff. */
+  /* Synched with FSF 20.6.  We added MINGW stuff. */
   PIMAGE_SECTION_HEADER section;
   int i;
 
@@ -2107,7 +2130,7 @@ void
 mswindows_executable_type (const char * filename, int * is_dos_app,
                           int * is_cygnus_app)
 {
-  /* Synched with FSF 20.6.  We added MINGW32 stuff and casts. */
+  /* Synched with FSF 20.6.  We added MINGW stuff and casts. */
   file_data executable;
   char * p;
 
@@ -2143,7 +2166,7 @@ mswindows_executable_type (const char * filename, int * is_dos_app,
         start with a DOS program stub.  Note that 16-bit Windows
         executables use the OS/2 1.x format. */
 
-#if 0 /* defined( __MINGW32__ ) */
+#if 0 /* defined( MINGW ) */
       /* mingw32 doesn't have enough headers to detect cygwin
         apps, just do what we can. */
       FILHDR * exe_header;
@@ -2214,6 +2237,83 @@ mswindows_executable_type (const char * filename, int * is_dos_app,
   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)