Include <config.h> instead of "config.h".
[bpt/emacs.git] / src / filelock.c
index df1794c..3955f38 100644 (file)
@@ -1,10 +1,10 @@
-/* Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+/* Copyright (C) 1985, 1986, 1987, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -19,10 +19,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "config.h"
+#include <config.h>
 
 #ifdef VMS
-#include "pwd.h"
+#include "vms-pwd.h"
 #else
 #include <pwd.h>
 #endif
@@ -33,13 +33,21 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <fcntl.h>
 #endif /* USG */
 
-#undef NULL
 #include "lisp.h"
 #include "paths.h"
 #include "buffer.h"
 
 extern int errno;
 
+extern char *egetenv ();
+extern char *strcpy ();
+
+#if defined (__bsdi__) || defined (DECLARE_GETPWUID_WITH_UID_T)
+extern struct passwd *getpwuid (uid_t);
+#else
+extern struct passwd *getpwuid ();
+#endif
+
 #ifdef CLASH_DETECTION
   
 /* If system does not have symbolic links, it does not have lstat.
@@ -49,13 +57,94 @@ extern int errno;
 #define lstat stat
 #endif
 
+
+/* The name of the directory in which we keep lock files, with a '/'
+   appended.  */  
+char *lock_path;
+
+/* The name of the file in the lock directory which is used to
+   arbitrate access to the entire directory.  */
+#define SUPERLOCK_NAME "!!!SuperLock!!!"
+
+/* The path to the superlock file.  This is SUPERLOCK_NAME appended to
+   lock_path.  */
+char *superlock_path;
+
+/* Set LOCK to the name of the lock file for the filename FILE.
+   char *LOCK; Lisp_Object FILE;  */
+
+#ifndef HAVE_LONG_FILE_NAMES
+
+#define MAKE_LOCK_PATH(lock, file) \
+  (lock = (char *) alloca (14 + strlen (lock_path) + 1), \
+   fill_in_lock_short_file_name (lock, (file)))
+
+
+fill_in_lock_short_file_name (lockfile, fn)
+     register char *lockfile;
+     register Lisp_Object fn;
+{
+  register union
+    {
+      unsigned int  word [2];
+      unsigned char byte [8];
+    } crc;
+  register unsigned char *p, new;
+  
+  /* 7-bytes cyclic code for burst correction on byte-by-byte basis.
+     the used polynomial is D^7 + D^6 + D^3 +1. pot@cnuce.cnr.it */
+
+  crc.word[0] = crc.word[1] = 0;
+
+  for (p = XSTRING (fn)->data; new = *p++; )
+    {
+      new += crc.byte[6];
+      crc.byte[6] = crc.byte[5] + new;
+      crc.byte[5] = crc.byte[4];
+      crc.byte[4] = crc.byte[3];
+      crc.byte[3] = crc.byte[2] + new;
+      crc.byte[2] = crc.byte[1];
+      crc.byte[1] = crc.byte[0];
+      crc.byte[0] = new;
+    }
+  sprintf (lockfile, "%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x", lock_path,
+          crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3],
+          crc.byte[4], crc.byte[5], crc.byte[6]);
+}
+
+#else /* defined HAVE_LONG_FILE_NAMES */
+
+#define MAKE_LOCK_PATH(lock, file) \
+  (lock = (char *) alloca (XSTRING (file)->size + strlen (lock_path) + 1), \
+   fill_in_lock_file_name (lock, (file)))
+
+
+fill_in_lock_file_name (lockfile, fn)
+     register char *lockfile;
+     register Lisp_Object fn;
+{
+  register char *p;
+
+  strcpy (lockfile, lock_path);
+
+  p = lockfile + strlen (lockfile);
+
+  strcpy (p, XSTRING (fn)->data);
+
+  for (; *p; p++)
+    {
+      if (*p == '/')
+       *p = '!';
+    }
+}
+#endif /* !defined HAVE_LONG_FILE_NAMES */
+
 static Lisp_Object
 lock_file_owner_name (lfname)
      char *lfname;
 {
   struct stat s;
   struct passwd *the_pw;
-  extern struct passwd *getpwuid ();
 
   if (lstat (lfname, &s) == 0)
     the_pw = getpwuid (s.st_uid);
@@ -84,6 +173,11 @@ lock_file_owner_name (lfname)
    and put in the Emacs lock directory.  */
 /* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
 
+/* If HAVE_LONG_FILE_NAMES is not defined, the lock file name is the hex
+   representation of a 14-bytes CRC generated from the file name
+   and put in the Emacs lock directory (not very nice, but it works).
+   (ie., /ka/king/junk.tex -> /!/12a82c62f1c6da). */
+
 void
 lock_file (fn)
      register Lisp_Object fn;
@@ -91,16 +185,15 @@ lock_file (fn)
   register Lisp_Object attack;
   register char *lfname;
 
-  /* Create the name of the lock-file for file fn */
-  lfname = (char *) alloca (XSTRING (fn)->size + strlen (PATH_LOCK) + 1);
-  fill_in_lock_file_name (lfname, fn);
+  MAKE_LOCK_PATH (lfname, fn);
 
-  /* See if this file is visited and has changed on disk since it was visited.  */
+  /* See if this file is visited and has changed on disk since it was
+     visited.  */
   {
     register Lisp_Object subject_buf = Fget_file_buffer (fn);
-    if (!NULL (subject_buf)
-       && NULL (Fverify_visited_file_modtime (subject_buf))
-       && !NULL (Ffile_exists_p (fn)))
+    if (!NILP (subject_buf)
+       && NILP (Fverify_visited_file_modtime (subject_buf))
+       && !NILP (Ffile_exists_p (fn)))
       call1 (intern ("ask-user-about-supersession-threat"), fn);
   }
 
@@ -112,36 +205,17 @@ lock_file (fn)
   /* Else consider breaking the lock */
   attack = call2 (intern ("ask-user-about-lock"), fn,
                  lock_file_owner_name (lfname));
-  if (!NULL (attack))
+  if (!NILP (attack))
     /* User says take the lock */
     {
       lock_superlock (lfname);
       lock_file_1 (lfname, O_WRONLY) ;
-      unlink (PATH_SUPERLOCK);
+      unlink (superlock_path);
       return;
     }
   /* User says ignore the lock */
 }
 
-fill_in_lock_file_name (lockfile, fn)
-     register char *lockfile;
-     register Lisp_Object fn;
-{
-  register char *p;
-
-  strcpy (lockfile, PATH_LOCK);
-
-  p = lockfile + strlen (lockfile);
-
-  strcpy (p, XSTRING (fn)->data);
-
-  for (; *p; p++)
-    {
-      if (*p == '/')
-       *p = '!';
-    }
-}
-
 /* Lock the lock file named LFNAME.
    If MODE is O_WRONLY, we do so even if it is already locked.
    If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
@@ -237,15 +311,14 @@ unlock_file (fn)
 {
   register char *lfname;
 
-  lfname = (char *) alloca (XSTRING (fn)->size + strlen (PATH_LOCK) + 1);
-  fill_in_lock_file_name (lfname, fn);
+  MAKE_LOCK_PATH (lfname, fn);
 
   lock_superlock (lfname);
 
   if (current_lock_owner_1 (lfname) == getpid ())
     unlink (lfname);
 
-  unlink (PATH_SUPERLOCK);
+  unlink (superlock_path);
 }
 
 lock_superlock (lfname)
@@ -253,7 +326,7 @@ lock_superlock (lfname)
 {
   register int i, fd;
 
-  for (i = -20; i < 0 && (fd = open (PATH_SUPERLOCK,
+  for (i = -20; i < 0 && (fd = open (superlock_path,
                                     O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
        i++)
     {
@@ -264,7 +337,7 @@ lock_superlock (lfname)
   if (fd >= 0)
     {
 #ifdef USG
-      chmod (PATH_SUPERLOCK, 0666);
+      chmod (superlock_path, 0666);
 #else
       fchmod (fd, 0666);
 #endif
@@ -298,12 +371,12 @@ or else nothing is done if current buffer isn't visiting a file.")
   (fn)
      Lisp_Object fn;
 {
-  if (NULL (fn))
+  if (NILP (fn))
     fn = current_buffer->filename;
   else
     CHECK_STRING (fn, 0);
   if (current_buffer->save_modified < MODIFF
-      && !NULL (fn))
+      && !NILP (fn))
     lock_file (fn);
   return Qnil;    
 }
@@ -342,9 +415,7 @@ t if it is locked by you, else a string of the name of the locker.")
 
   fn = Fexpand_file_name (fn, Qnil);
 
-  /* Create the name of the lock-file for file filename */
-  lfname = (char *) alloca (XSTRING (fn)->size + strlen (PATH_LOCK) + 1);
-  fill_in_lock_file_name (lfname, fn);
+  MAKE_LOCK_PATH (lfname, fn);
 
   owner = current_lock_owner (lfname);
   if (owner <= 0)
@@ -355,6 +426,30 @@ t if it is locked by you, else a string of the name of the locker.")
   return (lock_file_owner_name (lfname));
 }
 
+\f
+/* Initialization functions.  */
+
+init_filelock ()
+{
+  lock_path = egetenv ("EMACSLOCKDIR");
+  if (! lock_path)
+    lock_path = PATH_LOCK;
+
+  /* Make sure it ends with a slash.  */
+  if (lock_path[strlen (lock_path) - 1] != '/')
+    {
+      char *new_path = (char *) xmalloc (strlen (lock_path) + 2);
+      strcpy (new_path, lock_path);
+      lock_path = new_path;
+      strcat (lock_path, "/");
+    }
+
+  superlock_path = (char *) xmalloc ((strlen (lock_path)
+                                     + sizeof (SUPERLOCK_NAME)));
+  strcpy (superlock_path, lock_path);
+  strcat (superlock_path, SUPERLOCK_NAME);
+}
+
 syms_of_filelock ()
 {
   defsubr (&Sunlock_buffer);