* fileio.c (time_error_value): Check the right error number.
[bpt/emacs.git] / src / w32.c
index de72e18..9f57a8d 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,5 +1,5 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
-   Copyright (C) 1994-1995, 2000-2011  Free Software Foundation, Inc.
+   Copyright (C) 1994-1995, 2000-2012  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -94,8 +94,10 @@ typedef struct _MEMORY_STATUS_EX {
 
 #include <tlhelp32.h>
 #include <psapi.h>
+#ifndef _MSC_VER
 #include <w32api.h>
-#if !defined(__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
+#endif
+#if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
 /* This either is not in psapi.h or guarded by higher value of
    _WIN32_WINNT than what we use.  w32api supplied with MinGW 3.15
    defines it in psapi.h  */
@@ -316,8 +318,10 @@ is_windows_9x (void)
   return s_b_ret;
 }
 
+static Lisp_Object ltime (ULONGLONG);
+
 /* Get total user and system times for get-internal-run-time.
-   Returns a list of three integers if the times are provided by the OS
+   Returns a list of integers if the times are provided by the OS
    (NT derivatives), otherwise it returns the result of current-time. */
 Lisp_Object
 w32_get_internal_run_time (void)
@@ -329,27 +333,12 @@ w32_get_internal_run_time (void)
       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
         {
           LARGE_INTEGER user_int, kernel_int, total;
-          int microseconds;
           user_int.LowPart = user.dwLowDateTime;
           user_int.HighPart = user.dwHighDateTime;
           kernel_int.LowPart = kernel.dwLowDateTime;
           kernel_int.HighPart = kernel.dwHighDateTime;
           total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
-          /* FILETIME is 100 nanosecond increments, Emacs only wants
-             microsecond resolution.  */
-          total.QuadPart /= 10;
-          microseconds = total.QuadPart % 1000000;
-          total.QuadPart /= 1000000;
-
-          /* Sanity check to make sure we can represent the result.  */
-          if (total.HighPart == 0)
-            {
-              int secs = total.LowPart;
-
-              return list3 (make_number ((secs >> 16) & 0xffff),
-                            make_number (secs & 0xffff),
-                            make_number (microseconds));
-            }
+         return ltime (total.QuadPart);
         }
     }
 
@@ -789,9 +778,8 @@ getwd (char *dir)
     return dir;
   return NULL;
 #else
-  /* Emacs doesn't actually change directory itself, and we want to
-     force our real wd to be where emacs.exe is to avoid unnecessary
-     conflicts when trying to rename or delete directories.  */
+  /* Emacs doesn't actually change directory itself, it stays in the
+     same directory where it was started.  */
   strcpy (dir, startup_dir);
   return dir;
 #endif
@@ -1547,7 +1535,7 @@ init_environment (char ** argv)
         read-only filesystem, like CD-ROM or a write-protected floppy.
         The only way to be really sure is to actually create a file and
         see if it succeeds.  But I think that's too much to ask.  */
-      if (tmp && _access (tmp, D_OK) == 0)
+      if (tmp && sys_access (tmp, D_OK) == 0)
        {
          char * var = alloca (strlen (tmp) + 8);
          sprintf (var, "TMPDIR=%s", tmp);
@@ -1647,6 +1635,24 @@ init_environment (char ** argv)
         }
     }
 
+  /* When Emacs is invoked with --no-site-lisp, we must remove the
+     site-lisp directories from the default value of EMACSLOADPATH.
+     This assumes that the site-lisp entries are at the front, and
+     that additional entries do exist.  */
+  if (no_site_lisp)
+    {
+      for (i = 0; i < N_ENV_VARS; i++)
+        {
+          if (strcmp (env_vars[i].name, "EMACSLOADPATH") == 0)
+            {
+              char *site;
+              while ((site = strstr (env_vars[i].def_value, "site-lisp")))
+                env_vars[i].def_value = strchr (site, ';') + 1;
+              break;
+            }
+        }
+    }
+
 #define SET_ENV_BUF_SIZE (4 * MAX_PATH)        /* to cover EMACSLOADPATH */
 
     /* Treat emacs_dir specially: set it unconditionally based on our
@@ -1769,27 +1775,15 @@ init_environment (char ** argv)
        memcpy (*envp, "COMSPEC=", 8);
   }
 
-  /* Remember the initial working directory for getwd, then make the
-     real wd be the location of emacs.exe to avoid conflicts when
-     renaming or deleting directories.  (We also don't call chdir when
-     running subprocesses for the same reason.)  */
+  /* Remember the initial working directory for getwd.  */
   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);
-
-    /* Ensure argv[0] has the full path to Emacs.  */
-    *p = '\\';
     argv[0] = modname;
   }
 
@@ -1914,6 +1908,9 @@ get_emacs_configuration_options (void)
     cv,  /* To be filled later.  */
 #ifdef EMACSDEBUG
     " --no-opt",
+#endif
+#ifdef ENABLE_CHECKING
+    " --enable-checking",
 #endif
     /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
        with a starting space to save work here.  */
@@ -1980,6 +1977,41 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
     }
 }
 
+/* Emulate fdutimens.  */
+
+/* Set the access and modification time stamps of FD (a.k.a. FILE) to be
+   TIMESPEC[0] and TIMESPEC[1], respectively.
+   FD must be either negative -- in which case it is ignored --
+   or a file descriptor that is open on FILE.
+   If FD is nonnegative, then FILE can be NULL, which means
+   use just futimes instead of utimes.
+   If TIMESPEC is null, FAIL.
+   Return 0 on success, -1 (setting errno) on failure.  */
+
+int
+fdutimens (int fd, char const *file, struct timespec const timespec[2])
+{
+  struct _utimbuf ut;
+
+  if (!timespec)
+    {
+      errno = ENOSYS;
+      return -1;
+    }
+  if (fd < 0 && !file)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  ut.actime = timespec[0].tv_sec;
+  ut.modtime = timespec[1].tv_sec;
+  if (fd >= 0)
+    return _futime (fd, &ut);
+  else
+    return _utime (file, &ut);
+}
+
+
 /* ------------------------------------------------------------------------- */
 /* IO support and wrapper functions for W32 API. */
 /* ------------------------------------------------------------------------- */
@@ -2617,7 +2649,8 @@ sys_access (const char * path, int mode)
 {
   DWORD attributes;
 
-  /* MSVC implementation doesn't recognize D_OK.  */
+  /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
+     newer versions blow up when passed D_OK.  */
   path = map_w32_filename (path, NULL);
   if (is_unc_volume (path))
     {
@@ -2629,9 +2662,17 @@ sys_access (const char * path, int mode)
     }
   else if ((attributes = GetFileAttributes (path)) == -1)
     {
-      /* Should try mapping GetLastError to errno; for now just indicate
-        that path doesn't exist.  */
-      errno = EACCES;
+      DWORD w32err = GetLastError ();
+
+      switch (w32err)
+       {
+       case ERROR_FILE_NOT_FOUND:
+         errno = ENOENT;
+         break;
+       default:
+         errno = EACCES;
+         break;
+       }
       return -1;
     }
   if ((mode & X_OK) != 0 && !is_exec (path))
@@ -2869,6 +2910,8 @@ sys_rename (const char * oldname, const char * newname)
 {
   BOOL result;
   char temp[MAX_PATH];
+  int newname_dev;
+  int oldname_dev;
 
   /* MoveFile on Windows 95 doesn't correctly change the short file name
      alias in a number of circumstances (it is not easy to predict when
@@ -2885,6 +2928,9 @@ sys_rename (const char * oldname, const char * newname)
 
   strcpy (temp, map_w32_filename (oldname, NULL));
 
+  /* volume_info is set indirectly by map_w32_filename.  */
+  oldname_dev = volume_info.serialnum;
+
   if (os_subtype == OS_WIN95)
     {
       char * o;
@@ -2892,12 +2938,12 @@ sys_rename (const char * oldname, const char * newname)
       int    i = 0;
 
       oldname = map_w32_filename (oldname, NULL);
-      if (o = strrchr (oldname, '\\'))
+      if ((o = strrchr (oldname, '\\')))
        o++;
       else
        o = (char *) oldname;
 
-      if (p = strrchr (temp, '\\'))
+      if ((p = strrchr (temp, '\\')))
        p++;
       else
        p = temp;
@@ -2928,13 +2974,38 @@ sys_rename (const char * oldname, const char * newname)
      all the permutations of shared or subst'd drives, etc.)  */
 
   newname = map_w32_filename (newname, NULL);
+
+  /* volume_info is set indirectly by map_w32_filename.  */
+  newname_dev = volume_info.serialnum;
+
   result = rename (temp, newname);
 
-  if (result < 0
-      && errno == EEXIST
-      && _chmod (newname, 0666) == 0
-      && _unlink (newname) == 0)
-    result = rename (temp, newname);
+  if (result < 0)
+    {
+
+      if (errno == EACCES
+         && newname_dev != oldname_dev)
+       {
+         /* The implementation of `rename' on Windows does not return
+            errno = EXDEV when you are moving a directory to a
+            different storage device (ex. logical disk).  It returns
+            EACCES instead.  So here we handle such situations and
+            return EXDEV.  */
+         DWORD attributes;
+
+         if ((attributes = GetFileAttributes (temp)) != -1
+             && attributes & FILE_ATTRIBUTE_DIRECTORY)
+           errno = EXDEV;
+       }
+      else if (errno == EEXIST)
+       {
+         if (_chmod (newname, 0666) != 0)
+           return result;
+         if (_unlink (newname) != 0)
+           return result;
+         result = rename (temp, newname);
+       }
+    }
 
   return result;
 }
@@ -3050,7 +3121,7 @@ generate_inode_val (const char * name)
   unsigned hash;
 
   /* Get the truly canonical filename, if it exists.  (Note: this
-     doesn't resolve aliasing due to subst commands, or recognise hard
+     doesn't resolve aliasing due to subst commands, or recognize hard
      links.  */
   if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
     abort ();
@@ -3396,7 +3467,7 @@ stat (const char * path, struct stat * buf)
                           FILE_FLAG_BACKUP_SEMANTICS, NULL))
          != INVALID_HANDLE_VALUE)
     {
-      /* This is more accurate in terms of gettting the correct number
+      /* This is more accurate in terms of getting the correct number
         of links, but is quite slow (it is noticeable when Emacs is
         making a list of file name completions). */
       BY_HANDLE_FILE_INFORMATION info;
@@ -4013,14 +4084,17 @@ restore_privilege (TOKEN_PRIVILEGES *priv)
 }
 
 static Lisp_Object
-ltime (long time_sec, long time_usec)
+ltime (ULONGLONG time_100ns)
 {
-  return list3 (make_number ((time_sec >> 16) & 0xffff),
+  ULONGLONG time_sec = time_100ns / 10000000;
+  int subsec = time_100ns % 10000000;
+  return list4 (make_number (time_sec >> 16),
                make_number (time_sec & 0xffff),
-               make_number (time_usec));
+               make_number (subsec / 10),
+               make_number (subsec % 10 * 100000));
 }
 
-#define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
+#define U64_TO_LISP_TIME(time) ltime (time)
 
 static int
 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
@@ -4039,11 +4113,9 @@ process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
   GetSystemTimeAsFileTime (&ft_current);
 
   FILETIME_TO_U64 (tem1, ft_kernel);
-  tem1 /= 10L;
   *stime = U64_TO_LISP_TIME (tem1);
 
   FILETIME_TO_U64 (tem2, ft_user);
-  tem2 /= 10L;
   *utime = U64_TO_LISP_TIME (tem2);
 
   tem3 = tem1 + tem2;
@@ -4052,13 +4124,13 @@ process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
   FILETIME_TO_U64 (tem, ft_creation);
   /* Process no 4 (System) returns zero creation time.  */
   if (tem)
-    tem = (tem - utc_base) / 10L;
+    tem -= utc_base;
   *ctime = U64_TO_LISP_TIME (tem);
 
   if (tem)
     {
       FILETIME_TO_U64 (tem3, ft_current);
-      tem = (tem3 - utc_base) / 10L - tem;
+      tem = (tem3 - utc_base) - tem;
     }
   *etime = U64_TO_LISP_TIME (tem);
 
@@ -5756,9 +5828,17 @@ w32_delayed_load (Lisp_Object libraries, Lisp_Object library_id)
         for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
           {
             CHECK_STRING_CAR (dlls);
-            if (library_dll = LoadLibrary (SDATA (XCAR (dlls))))
+            if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
               {
-                found = XCAR (dlls);
+                char name[MAX_PATH];
+                DWORD len;
+
+                len = GetModuleFileNameA (library_dll, name, sizeof (name));
+                found = Fcons (XCAR (dlls),
+                               (len > 0)
+                               /* Possibly truncated */
+                               ? make_specified_string (name, -1, len, 1)
+                               : Qnil);
                 break;
               }
           }
@@ -5777,7 +5857,10 @@ check_windows_init_file (void)
      it cannot find the Windows installation file.  If this file does
      not exist in the expected place, tell the user.  */
 
-  if (!noninteractive && !inhibit_window_system)
+  if (!noninteractive && !inhibit_window_system
+      /* Vload_path is not yet initialized when we are loading
+        loadup.el.  */
+      && NILP (Vpurify_flag))
     {
       Lisp_Object objs[2];
       Lisp_Object full_load_path;
@@ -5835,7 +5918,7 @@ term_ntproc (void)
 void
 init_ntproc (void)
 {
-  /* Initialise the socket interface now if available and requested by
+  /* Initialize the socket interface now if available and requested by
      the user by defining PRELOAD_WINSOCK; otherwise loading will be
      delayed until open-network-stream is called (w32-has-winsock can
      also be used to dynamically load or reload winsock).
@@ -6206,13 +6289,13 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
   int n, sc, err;
   SELECT_TYPE fdset;
-  EMACS_TIME timeout;
+  struct timeval timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;
 
   for (;;)
     {
-      n = sys_read(fd, (char*)buf, sz);
+      n = sys_read (fd, (char*)buf, sz);
 
       if (n >= 0)
         return n;
@@ -6222,13 +6305,14 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
       if (err == EWOULDBLOCK)
         {
           /* Set a small timeout.  */
-          EMACS_SET_SECS_USECS(timeout, 1, 0);
+         timeout.tv_sec = 1;
+         timeout.tv_usec = 0;
           FD_ZERO (&fdset);
           FD_SET ((int)fd, &fdset);
 
           /* Use select with the timeout to poll the selector.  */
           sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
-                       &timeout);
+                       &timeout, NULL);
 
           if (sc > 0)
             continue;  /* Try again.  */
@@ -6252,7 +6336,7 @@ emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
 {
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->outfd;
-  ssize_t n = sys_write(fd, buf, sz);
+  ssize_t n = sys_write (fd, buf, sz);
 
   /* 0 or more bytes written means everything went fine.  */
   if (n >= 0)