home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / filelock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-04  |  10.7 KB  |  433 lines

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