declare smobs in alloc.c
[bpt/emacs.git] / src / filelock.c
index de6aba8..3a26814 100644 (file)
@@ -1,6 +1,10 @@
 /* Lock files for editing.
-   Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2013 Free Software
-   Foundation, Inc.
+
+Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2014
+  Free Software Foundation, Inc.
+
+Author: Richard King
+  (according to authors.el)
 
 This file is part of GNU Emacs.
 
@@ -47,11 +51,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "systime.h"
 #ifdef WINDOWSNT
 #include <share.h>
+#include <sys/socket.h>        /* for fcntl */
 #include "w32.h"       /* for dostounix_filename */
 #endif
 
-#ifdef CLASH_DETECTION
-
 #ifdef HAVE_UTMP_H
 #include <utmp.h>
 #endif
@@ -180,7 +183,7 @@ get_boot_time (void)
      since utmp is typically much smaller than wtmp.
      Passing a null pointer causes get_boot_time_1
      to inspect the default file, namely utmp.  */
-  get_boot_time_1 ((char *) 0, 0);
+  get_boot_time_1 (0, 0);
   if (boot_time)
     return boot_time;
 
@@ -256,18 +259,14 @@ void
 get_boot_time_1 (const char *filename, bool newest)
 {
   struct utmp ut, *utp;
-  int desc;
 
   if (filename)
     {
       /* On some versions of IRIX, opening a nonexistent file name
         is likely to crash in the utmp routines.  */
-      desc = emacs_open (filename, O_RDONLY, 0);
-      if (desc < 0)
+      if (faccessat (AT_FDCWD, filename, R_OK, AT_EACCESS) != 0)
        return;
 
-      emacs_close (desc);
-
       utmpname (filename);
     }
 
@@ -380,9 +379,9 @@ rename_lock_file (char const *old, char const *new, bool force)
 #endif
 }
 
-/* Create the lock file FILE with contents CONTENTS.  Return 0 if
+/* Create the lock file LFNAME with contents LOCK_INFO_STR.  Return 0 if
    successful, an errno value on failure.  If FORCE, remove any
-   existing FILE if necessary.  */
+   existing LFNAME if necessary.  */
 
 static int
 create_lock_file (char *lfname, char *lock_info_str, bool force)
@@ -411,31 +410,23 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
       USE_SAFE_ALLOCA;
       char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base);
       int fd;
-      bool need_fchmod;
-      mode_t world_readable = S_IRUSR | S_IRGRP | S_IROTH;
       memcpy (nonce, lfname, lfdirlen);
       strcpy (nonce + lfdirlen, nonce_base);
 
-#if HAVE_MKSTEMP
-      /* Prefer mkstemp if available, as it avoids a race between
-        mktemp and emacs_open.  */
-      fd = mkstemp (nonce);
-      need_fchmod = 1;
-#else
-      mktemp (nonce);
-      fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
-                      world_readable);
-      need_fchmod = 0;
-#endif
-
+      fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
       if (fd < 0)
        err = errno;
       else
        {
-         ptrdiff_t lock_info_len = strlen (lock_info_str);
+         ptrdiff_t lock_info_len;
+         if (! O_CLOEXEC)
+           fcntl (fd, F_SETFD, FD_CLOEXEC);
+         lock_info_len = strlen (lock_info_str);
          err = 0;
-         if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
-             || (need_fchmod && fchmod (fd, world_readable) != 0))
+         /* Use 'write', not 'emacs_write', as garbage collection
+            might signal an error, which would leak FD.  */
+         if (write (fd, lock_info_str, lock_info_len) != lock_info_len
+             || fchmod (fd, S_IRUSR | S_IRGRP | S_IROTH) != 0)
            err = errno;
          /* There is no need to call fsync here, as the contents of
             the lock file need not survive system crashes.  */
@@ -470,10 +461,18 @@ lock_file_1 (char *lfname, bool force)
   char lock_info_str[MAX_LFINFO + 1];
   printmax_t pid = getpid ();
 
-  if (sizeof lock_info_str
-      <= snprintf (lock_info_str, sizeof lock_info_str,
-                  boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
-                  user_name, host_name, pid, boot))
+  if (boot)
+    {
+      if (sizeof lock_info_str
+          <= snprintf (lock_info_str, sizeof lock_info_str,
+                       "%s@%s.%"pMd":%"pMd,
+                       user_name, host_name, pid, boot))
+        return ENAMETOOLONG;
+    }
+  else if (sizeof lock_info_str
+           <= snprintf (lock_info_str, sizeof lock_info_str,
+                        "%s@%s.%"pMd,
+                        user_name, host_name, pid))
     return ENAMETOOLONG;
 
   return create_lock_file (lfname, lock_info_str, force);
@@ -507,7 +506,8 @@ read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1])
       int fd = emacs_open (lfname, O_RDONLY | O_BINARY | O_NOFOLLOW, 0);
       if (0 <= fd)
        {
-         ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1);
+         /* Use read, not emacs_read, since FD isn't unwind-protected.  */
+         ptrdiff_t read_bytes = read (fd, lfinfo, MAX_LFINFO + 1);
          int read_errno = errno;
          if (emacs_close (fd) != 0)
            return -1;
@@ -691,7 +691,7 @@ lock_file (Lisp_Object fn)
   /* Ensure we have only '/' separators, to avoid problems with
      looking (inside fill_in_lock_file_name) for backslashes in file
      names encoded by some DBCS codepage.  */
-  dostounix_filename (SSDATA (fn), 1);
+  dostounix_filename (SSDATA (fn));
 #endif
   encoded_fn = ENCODE_FILE (fn);
 
@@ -755,16 +755,15 @@ unlock_file (Lisp_Object fn)
 void
 unlock_all_files (void)
 {
-  register Lisp_Object tail;
+  register Lisp_Object tail, buf;
   register struct buffer *b;
 
-  for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
+  FOR_EACH_LIVE_BUFFER (tail, buf)
     {
-      b = XBUFFER (XCDR (XCAR (tail)));
-      if (STRINGP (BVAR (b, file_truename)) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
-       {
-         unlock_file (BVAR (b, file_truename));
-       }
+      b = XBUFFER (buf);
+      if (STRINGP (BVAR (b, file_truename))
+         && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
+       unlock_file (BVAR (b, file_truename));
     }
 }
 \f
@@ -772,7 +771,9 @@ DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
        0, 1, 0,
        doc: /* Lock FILE, if current buffer is modified.
 FILE defaults to current buffer's visited file,
-or else nothing is done if current buffer isn't visiting a file.  */)
+or else nothing is done if current buffer isn't visiting a file.
+
+If the option `create-lockfiles' is nil, this does nothing.  */)
   (Lisp_Object file)
 {
   if (NILP (file))
@@ -836,11 +837,11 @@ t if it is locked by you, else a string saying which user has locked it.  */)
   return ret;
 }
 
-#endif /* CLASH_DETECTION */
-
 void
 syms_of_filelock (void)
 {
+#include "filelock.x"
+
   DEFVAR_LISP ("temporary-file-directory", Vtemporary_file_directory,
               doc: /* The directory for writing temporary files.  */);
   Vtemporary_file_directory = Qnil;
@@ -848,10 +849,4 @@ syms_of_filelock (void)
   DEFVAR_BOOL ("create-lockfiles", create_lockfiles,
               doc: /* Non-nil means use lockfiles to avoid editing collisions.  */);
   create_lockfiles = 1;
-
-#ifdef CLASH_DETECTION
-  defsubr (&Sunlock_buffer);
-  defsubr (&Slock_buffer);
-  defsubr (&Sfile_locked_p);
-#endif
 }