home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / filelock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-28  |  9.7 KB  |  403 lines

  1. /* Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
  2.  
  3. This file is part of GNU Emacs.
  4.  
  5. GNU Emacs is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. GNU Emacs is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Emacs; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19.  
  20. #include <stdio.h>        /* For sprintf */
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include "config.h"
  24. #include <pwd.h>
  25. #include <errno.h>
  26. #include <sys/file.h>
  27. #ifdef USG
  28. #include <fcntl.h>
  29. #endif /* USG */
  30.  
  31. #include "lisp.h"
  32. #include "paths.h"
  33. #include "buffer.h"
  34.  
  35. extern int errno;
  36.  
  37. #ifdef CLASH_DETECTION
  38.   
  39. Lisp_Object Vlock_directory;
  40. Lisp_Object Vsuperlock_path;
  41.  
  42. /* If system does not have symbolic links, it does not have lstat.
  43.    In that case, use ordinary stat instead.  */
  44.  
  45. #ifndef S_IFLNK
  46. #define lstat stat
  47. #endif
  48.  
  49. static void fill_in_lock_file_name (), lock_superlock ();
  50.  
  51. static Lisp_Object
  52. lock_file_owner_name (lfname)
  53.      char *lfname;
  54. {
  55.   struct stat s;
  56.   struct passwd *the_pw;
  57.  
  58.   if (lstat (lfname, &s) == 0)
  59.     the_pw = getpwuid (s.st_uid);
  60.   return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
  61. }
  62.  
  63.  
  64. /* lock_file locks file fn,
  65.    meaning it serves notice on the world that you intend to edit that file.
  66.    This should be done only when about to modify a file-visiting
  67.    buffer previously unmodified.
  68.    Do not (normally) call lock_buffer for a buffer already modified,
  69.    as either the file is already locked, or the user has already
  70.    decided to go ahead without locking.
  71.  
  72.    When lock_buffer returns, either the lock is locked for us,
  73.    or the user has said to go ahead without locking.
  74.  
  75.    If the file is locked by someone else, lock_buffer calls
  76.    ask-user-about-lock (a Lisp function) with two arguments,
  77.    the file name and the name of the user who did the locking.
  78.    This function can signal an error, or return t meaning
  79.    take away the lock, or return nil meaning ignore the lock.  */
  80.  
  81. /* The lock file name is the file name with "/" replaced by "!"
  82.    and put in the Emacs lock directory.  */
  83. /* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
  84.  
  85. static int lock_file_1 ();
  86. static int lock_if_free ();
  87.  
  88. void
  89. lock_file (fn)
  90.      register Lisp_Object fn;
  91. {
  92.   register Lisp_Object attack;
  93.   register char *lfname;
  94.   if (NILP (Vlock_directory) || NILP (Vsuperlock_path)) return;
  95.   CHECK_STRING (Vlock_directory, 0);
  96.  
  97.   /* Create the name of the lock-file for file fn */
  98.   lfname = (char *) alloca (XSTRING (fn)->size +
  99.                 XSTRING (Vlock_directory)->size + 1);
  100.   fill_in_lock_file_name (lfname, fn);
  101.  
  102.   /* See if this file is visited and has changed on disk since it was visited.  */
  103.   {
  104.     register Lisp_Object subject_buf = Fget_file_buffer (fn);
  105.     if (!NILP (subject_buf)
  106.     && NILP (Fverify_visited_file_modtime (subject_buf))
  107.     && !NILP (Ffile_exists_p (fn)))
  108.       call1 (intern ("ask-user-about-supersession-threat"), fn);
  109.   }
  110.  
  111.   /* Try to lock the lock. */
  112.   if (lock_if_free (lfname) <= 0)
  113.     /* Return now if we have locked it, or if lock dir does not exist */
  114.     return;
  115.  
  116.   /* Else consider breaking the lock */
  117.   attack = call2 (intern ("ask-user-about-lock"), fn,
  118.           lock_file_owner_name (lfname));
  119.   if (!NILP (attack))
  120.     /* User says take the lock */
  121.     {
  122.       CHECK_STRING (Vsuperlock_path, 0);
  123.       lock_superlock (lfname);
  124.       lock_file_1 (lfname, O_WRONLY);
  125.       unlink ((char *) XSTRING (Vsuperlock_path)->data);
  126.       return;
  127.     }
  128.   /* User says ignore the lock */
  129. }
  130.  
  131. static void
  132. fill_in_lock_file_name (lockfile, fn)
  133.      register char *lockfile;
  134.      register Lisp_Object fn;
  135. {
  136.   register char *p;
  137.   CHECK_STRING (Vlock_directory, 0);
  138.  
  139.   strcpy (lockfile, (char*)XSTRING (Vlock_directory)->data);
  140.  
  141.   p = lockfile + strlen (lockfile);
  142.  
  143.   strcpy (p, (char*)XSTRING (fn)->data);
  144.  
  145.   for (; *p; p++)
  146.     {
  147.       if (*p == '/')
  148.     *p = '!';
  149.     }
  150. }
  151.  
  152. /* Lock the lock file named LFNAME.
  153.    If MODE is O_WRONLY, we do so even if it is already locked.
  154.    If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
  155.    Return 1 if successful, 0 if not.  */
  156.  
  157. static int
  158. lock_file_1 (lfname, mode)
  159.      int mode; char *lfname; 
  160. {
  161.   register int fd;
  162.   char buf[20];
  163.  
  164.   if ((fd = open (lfname, mode, 0666)) >= 0)
  165.     {
  166. #ifdef USG
  167.       chmod (lfname, 0666);
  168. #else
  169.       fchmod (fd, 0666);
  170. #endif
  171.       sprintf (buf, "%d ", getpid ());
  172.       write (fd, buf, strlen (buf));
  173.       close (fd);
  174.       return 1;
  175.     }
  176.   else
  177.     return 0;
  178. }
  179.  
  180. static int current_lock_owner ();
  181.  
  182. /* Lock the lock named LFNAME if possible.
  183.    Return 0 in that case.
  184.    Return positive if lock is really locked by someone else.
  185.    Return -1 if cannot lock for any other reason.  */
  186.  
  187. static int
  188. lock_if_free (lfname)
  189.      register char *lfname; 
  190. {
  191.   register int clasher;
  192.  
  193.   while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
  194.     {
  195.       if (errno != EEXIST)
  196.     return -1;
  197.       clasher = current_lock_owner (lfname);
  198.       if (clasher != 0)
  199.     if (clasher != getpid ())
  200.       return (clasher);
  201.     else return (0);
  202.       /* Try again to lock it */
  203.     }
  204.   return 0;
  205. }
  206.  
  207. static int current_lock_owner_1 ();
  208.  
  209. /* Return the pid of the process that claims to own the lock file LFNAME,
  210.    or 0 if nobody does or the lock is obsolete,
  211.    or -1 if something is wrong with the locking mechanism.  */
  212.  
  213. static int
  214. current_lock_owner (lfname)
  215.      char *lfname;
  216. {
  217.   int owner = current_lock_owner_1 (lfname);
  218.   if (owner == 0 && errno == ENOENT)
  219.     return (0);
  220.   /* Is it locked by a process that exists?  */
  221.   if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
  222.     return (owner);
  223.   if (unlink (lfname) < 0)
  224.     return (-1);
  225.   return (0);
  226. }
  227.  
  228. static int
  229. current_lock_owner_1 (lfname)
  230.      char *lfname;
  231. {
  232.   register int fd;
  233.   char buf[20];
  234.   int tem;
  235.  
  236.   fd = open (lfname, O_RDONLY, 0666);
  237.   if (fd < 0)
  238.     return 0;
  239.   tem = read (fd, buf, sizeof buf);
  240.   close (fd);
  241.   return (tem <= 0 ? 0 : atoi (buf));
  242. }
  243.  
  244.  
  245. void
  246. unlock_file (fn)
  247.      register Lisp_Object fn;
  248. {
  249.   register char *lfname;
  250.   if (NILP (Vlock_directory) || NILP (Vsuperlock_path)) return;
  251.   CHECK_STRING (Vlock_directory, 0);
  252.   CHECK_STRING (Vsuperlock_path, 0);
  253.  
  254.   lfname = (char *) alloca (XSTRING (fn)->size +
  255.                 XSTRING (Vlock_directory)->size + 1);
  256.   fill_in_lock_file_name (lfname, fn);
  257.  
  258.   lock_superlock (lfname);
  259.  
  260.   if (current_lock_owner_1 (lfname) == getpid ())
  261.     unlink (lfname);
  262.  
  263.   unlink ((char *) XSTRING (Vsuperlock_path)->data);
  264. }
  265.  
  266. static void
  267. lock_superlock (lfname)
  268.      char *lfname;
  269. {
  270.   register int i, fd;
  271.   CHECK_STRING (Vsuperlock_path, 0);
  272.  
  273.   for (i = -20; i < 0 &&
  274.        (fd = open ((char *)XSTRING (Vsuperlock_path)->data,
  275.            O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
  276.        i++)
  277.     {
  278.       if (errno != EEXIST)
  279.     return;
  280.       sleep (1);
  281.     }
  282.   if (fd >= 0)
  283.     {
  284. #ifdef USG
  285.       chmod ((char *) XSTRING (Vsuperlock_path)->data, 0666);
  286. #else
  287.       fchmod (fd, 0666);
  288. #endif
  289.       write (fd, lfname, strlen (lfname));
  290.       close (fd);
  291.     }
  292. }
  293.  
  294. void
  295. unlock_all_files ()
  296. {
  297.   register Lisp_Object tail;
  298.   register struct buffer *b;
  299.  
  300.   for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
  301.        tail = XCONS (tail)->cdr)
  302.     {
  303.       b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
  304.       if (STRINGP (b->filename) &&
  305.       b->save_modified < BUF_MODIFF (b))
  306.     unlock_file (b->filename);
  307.     }
  308. }
  309.  
  310.  
  311. DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
  312.   0, 1, 0,
  313.   "Lock FILE, if current buffer is modified.\n\
  314. FILE defaults to current buffer's visited file,\n\
  315. or else nothing is done if current buffer isn't visiting a file.")
  316.   (fn)
  317.      Lisp_Object fn;
  318. {
  319.   if (NILP (fn))
  320.     fn = current_buffer->filename;
  321.   else
  322.     CHECK_STRING (fn, 0);
  323.   if (current_buffer->save_modified < MODIFF
  324.       && !NILP (fn))
  325.     lock_file (fn);
  326.   return Qnil;    
  327. }
  328.  
  329. DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
  330.   0, 0, 0,
  331.  "Unlock the file visited in the current buffer,\n\
  332. if it should normally be locked.")
  333.   ()
  334. {
  335.   if (current_buffer->save_modified < MODIFF &&
  336.       STRINGP (current_buffer->filename))
  337.     unlock_file (current_buffer->filename);
  338.   return Qnil;
  339. }
  340.  
  341.  
  342. /* Unlock the file visited in buffer BUFFER.  */
  343.  
  344. void
  345. unlock_buffer (buffer)
  346.      struct buffer *buffer;
  347. {
  348.   if (buffer->save_modified < BUF_MODIFF (buffer) &&
  349.       STRINGP (buffer->filename))
  350.     unlock_file (buffer->filename);
  351. }
  352.  
  353. DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
  354.   "Return nil if the FILENAME is not locked,\n\
  355. t if it is locked by you, else a string of the name of the locker.")
  356.   (fn)
  357.   Lisp_Object fn;
  358. {
  359.   register char *lfname;
  360.   int owner;
  361.   if (NILP (Vlock_directory) || NILP (Vsuperlock_path))
  362.     return Qnil;
  363.   CHECK_STRING (Vlock_directory, 0);
  364.  
  365.   fn = Fexpand_file_name (fn, Qnil);
  366.  
  367.   /* Create the name of the lock-file for file filename */
  368.   lfname = (char *) alloca (XSTRING (fn)->size +
  369.                 XSTRING (Vlock_directory)->size + 1);
  370.   fill_in_lock_file_name (lfname, fn);
  371.  
  372.   owner = current_lock_owner (lfname);
  373.   if (owner <= 0)
  374.     return (Qnil);
  375.   else if (owner == getpid ())
  376.     return (Qt);
  377.   
  378.   return (lock_file_owner_name (lfname));
  379. }
  380.  
  381. void
  382. syms_of_filelock ()
  383. {
  384.   defsubr (&Sunlock_buffer);
  385.   defsubr (&Slock_buffer);
  386.   defsubr (&Sfile_locked_p);
  387.  
  388.   DEFVAR_LISP ("lock-directory", &Vlock_directory, "Don't change this");
  389.   DEFVAR_LISP ("superlock-path", &Vsuperlock_path, "Don't change this");
  390. #ifdef PATH_LOCK
  391.   Vlock_directory = build_string (PATH_LOCK);
  392. #else
  393.   Vlock_directory = Qnil;
  394. #endif
  395. #ifdef PATH_SUPERLOCK
  396.   Vsuperlock_path = build_string (PATH_SUPERLOCK);
  397. #else
  398.   Vsuperlock_path = Qnil;
  399. #endif
  400. }
  401.  
  402. #endif /* CLASH_DETECTION */
  403.