(authors-aliases): Add some more aliases.
[bpt/emacs.git] / src / filelock.c
CommitLineData
b97771fc
RS
1/* Lock files for editing.
2 Copyright (C) 1985, 86, 87, 93, 94, 96, 98, 1999 Free Software Foundation, Inc.
8489eb67
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
32676c08 8the Free Software Foundation; either version 2, or (at your option)
8489eb67
RS
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
8489eb67
RS
20
21
68c45bf0 22#include <config.h>
8489eb67
RS
23#include <sys/types.h>
24#include <sys/stat.h>
dfcf069d 25#include <signal.h>
2decc5a9 26#include <stdio.h>
bfb61299
JB
27
28#ifdef VMS
b350a838 29#include "vms-pwd.h"
bfb61299 30#else
8489eb67 31#include <pwd.h>
8dbbc384 32#endif /* not VMS */
bfb61299 33
8489eb67 34#include <sys/file.h>
e5ef3cdf 35#ifdef HAVE_FCNTL_H
8489eb67 36#include <fcntl.h>
e5ef3cdf
DL
37#endif
38#ifdef HAVE_STRING_H
8dbbc384 39#include <string.h>
e5ef3cdf 40#endif
8489eb67 41
dfcf069d
AS
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45
f805a125 46#ifdef __FreeBSD__
f805a125
KH
47#include <sys/sysctl.h>
48#endif /* __FreeBSD__ */
49
e5ef3cdf
DL
50#include <errno.h>
51#ifndef errno
52extern int errno;
53#endif
54
8489eb67 55#include "lisp.h"
8489eb67 56#include "buffer.h"
f4a4528d
RS
57#include "charset.h"
58#include "coding.h"
9177d978 59#include "systime.h"
8489eb67 60
5f8d6a10
RS
61/* The directory for writing temporary files. */
62
63Lisp_Object Vtemporary_file_directory;
64
8489eb67 65#ifdef CLASH_DETECTION
e788eecc
KH
66
67#include <utmp.h>
77e544a4 68
a48de9b2
PE
69/* A file whose last-modified time is just after the most recent boot.
70 Define this to be NULL to disable checking for this file. */
71#ifndef BOOT_TIME_FILE
72#define BOOT_TIME_FILE "/var/run/random-seed"
73#endif
74
77e544a4
RS
75#ifndef WTMP_FILE
76#define WTMP_FILE "/var/log/wtmp"
77#endif
8489eb67 78
8dbbc384
RS
79/* The strategy: to lock a file FN, create a symlink .#FN in FN's
80 directory, with link data `user@host.pid'. This avoids a single
81 mount (== failure) point for lock files.
82
83 When the host in the lock data is the current host, we can check if
84 the pid is valid with kill.
85
86 Otherwise, we could look at a separate file that maps hostnames to
87 reboot times to see if the remote pid can possibly be valid, since we
88 don't want Emacs to have to communicate via pipes or sockets or
89 whatever to other processes, either locally or remotely; rms says
90 that's too unreliable. Hence the separate file, which could
91 theoretically be updated by daemons running separately -- but this
92 whole idea is unimplemented; in practice, at least in our
1c4f857c 93 environment, it seems such stale locks arise fairly infrequently, and
8dbbc384
RS
94 Emacs' standard methods of dealing with clashes suffice.
95
96 We use symlinks instead of normal files because (1) they can be
97 stored more efficiently on the filesystem, since the kernel knows
98 they will be small, and (2) all the info about the lock can be read
99 in a single system call (readlink). Although we could use regular
1c4f857c 100 files to be useful on old systems lacking symlinks, nowadays
8dbbc384
RS
101 virtually all such systems are probably single-user anyway, so it
102 didn't seem worth the complication.
103
104 Similarly, we don't worry about a possible 14-character limit on
105 file names, because those are all the same systems that don't have
106 symlinks.
107
108 This is compatible with the locking scheme used by Interleaf (which
109 has contributed this implementation for Emacs), and was designed by
110 Ethan Jacobson, Kimbo Mundy, and others.
111
112 --karl@cs.umb.edu/karl@hq.ileaf.com. */
8489eb67 113
8dbbc384 114\f
15e88d21
RS
115/* Return the time of the last system boot. */
116
117static time_t boot_time;
b97771fc 118static int boot_time_initialized;
15e88d21 119
9177d978
RS
120extern Lisp_Object Vshell_file_name;
121
2f2500ef
DL
122#ifdef BOOT_TIME
123static void get_boot_time_1 P_ ((char *, int));
124#endif
125
15e88d21
RS
126static time_t
127get_boot_time ()
128{
2decc5a9 129#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
9177d978 130 int counter;
2decc5a9 131#endif
15e88d21 132
b97771fc 133 if (boot_time_initialized)
15e88d21 134 return boot_time;
b97771fc 135 boot_time_initialized = 1;
15e88d21 136
f805a125
KH
137#if defined (CTL_KERN) && defined (KERN_BOOTTIME)
138 {
139 int mib[2];
140 size_t size;
141 struct timeval boottime_val;
142
143 mib[0] = CTL_KERN;
144 mib[1] = KERN_BOOTTIME;
145 size = sizeof (boottime_val);
146
147 if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
148 {
149 boot_time = boottime_val.tv_sec;
150 return boot_time;
151 }
152 }
153#endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
9177d978 154
a48de9b2
PE
155 if (BOOT_TIME_FILE)
156 {
157 struct stat st;
158 if (stat (BOOT_TIME_FILE, &st) == 0)
159 {
160 boot_time = st.st_mtime;
161 return boot_time;
162 }
163 }
164
c6fd1dc4 165#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
b97771fc
RS
166#ifndef CANNOT_DUMP
167 /* The utmp routines maintain static state.
168 Don't touch that state unless we are initialized,
169 since it might not survive dumping. */
170 if (! initialized)
171 return boot_time;
172#endif /* not CANNOT_DUMP */
173
174 /* Try to get boot time from utmp before wtmp,
175 since utmp is typically much smaller than wtmp.
176 Passing a null pointer causes get_boot_time_1
177 to inspect the default file, namely utmp. */
178 get_boot_time_1 ((char *) 0, 0);
179 if (boot_time)
180 return boot_time;
181
9177d978 182 /* Try to get boot time from the current wtmp file. */
b97771fc 183 get_boot_time_1 (WTMP_FILE, 1);
9177d978
RS
184
185 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
b97771fc 186 for (counter = 0; counter < 20 && ! boot_time; counter++)
9177d978
RS
187 {
188 char cmd_string[100];
189 Lisp_Object tempname, filename;
190 int delete_flag = 0;
191
192 filename = Qnil;
193
77e544a4 194 sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
9177d978 195 tempname = build_string (cmd_string);
29a2adb0 196 if (! NILP (Ffile_exists_p (tempname)))
9177d978
RS
197 filename = tempname;
198 else
199 {
77e544a4 200 sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
9177d978
RS
201 tempname = build_string (cmd_string);
202 if (! NILP (Ffile_exists_p (tempname)))
203 {
204 Lisp_Object args[6];
f1d367aa
GM
205
206 /* The utmp functions on mescaline.gnu.org accept only
207 file names up to 8 characters long. Choose a 2
208 character long prefix, and call make_temp_file with
209 second arg non-zero, so that it will add not more
210 than 6 characters to the prefix. */
211 tempname = Fexpand_file_name (build_string ("wt"),
5f8d6a10 212 Vtemporary_file_directory);
f1d367aa 213 tempname = make_temp_name (tempname, 1);
9177d978
RS
214 args[0] = Vshell_file_name;
215 args[1] = Qnil;
216 args[2] = Qnil;
217 args[3] = Qnil;
218 args[4] = build_string ("-c");
77e544a4
RS
219 sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
220 WTMP_FILE, counter, XSTRING (tempname)->data);
9177d978
RS
221 args[5] = build_string (cmd_string);
222 Fcall_process (6, args);
223 filename = tempname;
224 delete_flag = 1;
225 }
226 }
227
228 if (! NILP (filename))
229 {
b97771fc 230 get_boot_time_1 (XSTRING (filename)->data, 1);
9177d978
RS
231 if (delete_flag)
232 unlink (XSTRING (filename)->data);
233 }
234 }
235
236 return boot_time;
237#else
238 return 0;
239#endif
240}
241
e9f22ced 242#ifdef BOOT_TIME
9177d978
RS
243/* Try to get the boot time from wtmp file FILENAME.
244 This succeeds if that file contains a reboot record.
9177d978 245
b97771fc
RS
246 If FILENAME is zero, use the same file as before;
247 if no FILENAME has ever been specified, this is the utmp file.
248 Use the newest reboot record if NEWEST is nonzero,
249 the first reboot record otherwise.
250 Ignore all reboot records on or before BOOT_TIME.
251 Success is indicated by setting BOOT_TIME to a larger value. */
252
2f2500ef 253void
b97771fc 254get_boot_time_1 (filename, newest)
9177d978 255 char *filename;
b97771fc 256 int newest;
9177d978
RS
257{
258 struct utmp ut, *utp;
77e544a4
RS
259 int desc;
260
b97771fc
RS
261 if (filename)
262 {
263 /* On some versions of IRIX, opening a nonexistent file name
264 is likely to crash in the utmp routines. */
68c45bf0 265 desc = emacs_open (filename, O_RDONLY, 0);
b97771fc
RS
266 if (desc < 0)
267 return;
268
68c45bf0 269 emacs_close (desc);
b97771fc
RS
270
271 utmpname (filename);
272 }
9177d978 273
c321b190 274 setutent ();
b97771fc 275
c321b190
RS
276 while (1)
277 {
278 /* Find the next reboot record. */
279 ut.ut_type = BOOT_TIME;
280 utp = getutid (&ut);
281 if (! utp)
282 break;
283 /* Compare reboot times and use the newest one. */
284 if (utp->ut_time > boot_time)
b97771fc
RS
285 {
286 boot_time = utp->ut_time;
287 if (! newest)
288 break;
289 }
c321b190
RS
290 /* Advance on element in the file
291 so that getutid won't repeat the same one. */
292 utp = getutent ();
293 if (! utp)
294 break;
295 }
15e88d21 296 endutent ();
15e88d21 297}
e9f22ced 298#endif /* BOOT_TIME */
15e88d21 299\f
8dbbc384 300/* Here is the structure that stores information about a lock. */
32676c08 301
8dbbc384
RS
302typedef struct
303{
304 char *user;
305 char *host;
9005cb4f 306 unsigned long pid;
15e88d21 307 time_t boot_time;
8dbbc384 308} lock_info_type;
32676c08 309
49b6d120
RS
310/* When we read the info back, we might need this much more,
311 enough for decimal representation plus null. */
312#define LOCK_PID_MAX (4 * sizeof (unsigned long))
32676c08 313
8dbbc384
RS
314/* Free the two dynamically-allocated pieces in PTR. */
315#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
e31fbc7a 316
e31fbc7a 317
8dbbc384 318/* Write the name of the lock file for FN into LFNAME. Length will be
c1355e1f
GM
319 that of FN plus two more for the leading `.#' plus 1 for the
320 trailing period plus one for the digit after it plus one for the
321 null. */
7b92975f 322#define MAKE_LOCK_NAME(lock, file) \
c1355e1f 323 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1 + 1 + 1), \
8dbbc384 324 fill_in_lock_file_name (lock, (file)))
e31fbc7a 325
8dbbc384
RS
326static void
327fill_in_lock_file_name (lockfile, fn)
e31fbc7a
RS
328 register char *lockfile;
329 register Lisp_Object fn;
330{
8dbbc384 331 register char *p;
c1355e1f
GM
332 struct stat st;
333 int count = 0;
8dbbc384
RS
334
335 strcpy (lockfile, XSTRING (fn)->data);
336
337 /* Shift the nondirectory part of the file name (including the null)
338 right two characters. Here is one of the places where we'd have to
339 do something to support 14-character-max file names. */
340 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
341 p[2] = *p;
e31fbc7a 342
8dbbc384
RS
343 /* Insert the `.#'. */
344 p[1] = '.';
345 p[2] = '#';
c1355e1f
GM
346
347 p = p + strlen (p);
348
349 while (lstat (lockfile, &st) == 0 && !S_ISLNK (st.st_mode))
350 {
351 if (count > 9)
352 {
353 *p = '\0';
354 return;
355 }
356 sprintf (p, ".%d", count++);
357 }
8dbbc384 358}
e31fbc7a 359
8dbbc384
RS
360/* Lock the lock file named LFNAME.
361 If FORCE is nonzero, we do so even if it is already locked.
362 Return 1 if successful, 0 if not. */
e31fbc7a 363
8dbbc384
RS
364static int
365lock_file_1 (lfname, force)
366 char *lfname;
367 int force;
368{
369 register int err;
bd26d5a3 370 time_t boot_time;
662c2ef2
RS
371 char *user_name;
372 char *host_name;
373 char *lock_info_str;
374
375 if (STRINGP (Fuser_login_name (Qnil)))
266d7a00 376 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
662c2ef2
RS
377 else
378 user_name = "";
379 if (STRINGP (Fsystem_name ()))
266d7a00 380 host_name = (char *)XSTRING (Fsystem_name ())->data;
662c2ef2
RS
381 else
382 host_name = "";
266d7a00 383 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
15e88d21 384 + LOCK_PID_MAX + 5);
8dbbc384 385
bd26d5a3
RS
386 boot_time = get_boot_time ();
387 if (boot_time)
388 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
389 (unsigned long) getpid (), (unsigned long) boot_time);
390 else
391 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
392 (unsigned long) getpid ());
8dbbc384
RS
393
394 err = symlink (lock_info_str, lfname);
395 if (errno == EEXIST && force)
e31fbc7a 396 {
8dbbc384
RS
397 unlink (lfname);
398 err = symlink (lock_info_str, lfname);
e31fbc7a 399 }
e31fbc7a 400
8dbbc384
RS
401 return err == 0;
402}
e31fbc7a 403
9177d978 404/* Return 1 if times A and B are no more than one second apart. */
32676c08 405
9177d978
RS
406int
407within_one_second (a, b)
408 time_t a, b;
409{
410 return (a - b >= -1 && a - b <= 1);
411}
8dbbc384
RS
412\f
413/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
414 1 if another process owns it (and set OWNER (if non-null) to info),
415 2 if the current process owns it,
416 or -1 if something is wrong with the locking mechanism. */
e31fbc7a 417
8dbbc384
RS
418static int
419current_lock_owner (owner, lfname)
420 lock_info_type *owner;
421 char *lfname;
32676c08 422{
8dbbc384
RS
423#ifndef index
424 extern char *rindex (), *index ();
425#endif
5f8d6a10 426 int len, ret;
8dbbc384 427 int local_owner = 0;
15e88d21 428 char *at, *dot, *colon;
8dbbc384
RS
429 char *lfinfo = 0;
430 int bufsize = 50;
431 /* Read arbitrarily-long contents of symlink. Similar code in
432 file-symlink-p in fileio.c. */
433 do
434 {
435 bufsize *= 2;
436 lfinfo = (char *) xrealloc (lfinfo, bufsize);
437 len = readlink (lfname, lfinfo, bufsize);
438 }
439 while (len >= bufsize);
440
441 /* If nonexistent lock file, all is well; otherwise, got strange error. */
442 if (len == -1)
443 {
444 xfree (lfinfo);
445 return errno == ENOENT ? 0 : -1;
446 }
32676c08 447
8dbbc384
RS
448 /* Link info exists, so `len' is its length. Null terminate. */
449 lfinfo[len] = 0;
450
451 /* Even if the caller doesn't want the owner info, we still have to
452 read it to determine return value, so allocate it. */
453 if (!owner)
454 {
3609a53b 455 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
8dbbc384
RS
456 local_owner = 1;
457 }
458
15e88d21 459 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
8dbbc384
RS
460 /* The USER is everything before the first @. */
461 at = index (lfinfo, '@');
462 dot = rindex (lfinfo, '.');
15e88d21
RS
463 if (!at || !dot)
464 {
465 xfree (lfinfo);
466 return -1;
467 }
8dbbc384
RS
468 len = at - lfinfo;
469 owner->user = (char *) xmalloc (len + 1);
470 strncpy (owner->user, lfinfo, len);
471 owner->user[len] = 0;
472
15e88d21 473 /* The PID is everything from the last `.' to the `:'. */
8dbbc384 474 owner->pid = atoi (dot + 1);
15e88d21
RS
475 colon = dot;
476 while (*colon && *colon != ':')
477 colon++;
478 /* After the `:', if there is one, comes the boot time. */
479 if (*colon == ':')
480 owner->boot_time = atoi (colon + 1);
481 else
482 owner->boot_time = 0;
32676c08 483
8dbbc384
RS
484 /* The host is everything in between. */
485 len = dot - at - 1;
486 owner->host = (char *) xmalloc (len + 1);
487 strncpy (owner->host, at + 1, len);
488 owner->host[len] = 0;
32676c08 489
8dbbc384
RS
490 /* We're done looking at the link info. */
491 xfree (lfinfo);
492
493 /* On current host? */
662c2ef2
RS
494 if (STRINGP (Fsystem_name ())
495 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
32676c08 496 {
8dbbc384
RS
497 if (owner->pid == getpid ())
498 ret = 2; /* We own it. */
72dcef0e 499 else if (owner->pid > 0
15e88d21
RS
500 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
501 && (owner->boot_time == 0
9177d978 502 || within_one_second (owner->boot_time, get_boot_time ())))
8dbbc384 503 ret = 1; /* An existing process on this machine owns it. */
8dbbc384
RS
504 /* The owner process is dead or has a strange pid (<=0), so try to
505 zap the lockfile. */
72dcef0e 506 else if (unlink (lfname) < 0)
8dbbc384 507 ret = -1;
72dcef0e
RS
508 else
509 ret = 0;
32676c08 510 }
8dbbc384
RS
511 else
512 { /* If we wanted to support the check for stale locks on remote machines,
513 here's where we'd do it. */
514 ret = 1;
515 }
516
517 /* Avoid garbage. */
518 if (local_owner || ret <= 0)
519 {
520 FREE_LOCK_INFO (*owner);
521 }
522 return ret;
32676c08
JB
523}
524
8dbbc384
RS
525\f
526/* Lock the lock named LFNAME if possible.
527 Return 0 in that case.
528 Return positive if some other process owns the lock, and info about
529 that process in CLASHER.
530 Return -1 if cannot lock for any other reason. */
8489eb67 531
8dbbc384
RS
532static int
533lock_if_free (clasher, lfname)
534 lock_info_type *clasher;
535 register char *lfname;
536{
cfc01fa7 537 while (lock_file_1 (lfname, 0) == 0)
8dbbc384
RS
538 {
539 int locker;
e0e0205b 540
8dbbc384
RS
541 if (errno != EEXIST)
542 return -1;
543
544 locker = current_lock_owner (clasher, lfname);
545 if (locker == 2)
546 {
547 FREE_LOCK_INFO (*clasher);
548 return 0; /* We ourselves locked it. */
549 }
550 else if (locker == 1)
551 return 1; /* Someone else has it. */
5df0b2fa 552 else if (locker == -1)
ae1ef097 553 return -1; /* current_lock_owner returned strange error. */
8dbbc384 554
cfc01fa7 555 /* We deleted a stale lock; try again to lock the file. */
8dbbc384
RS
556 }
557 return 0;
8489eb67
RS
558}
559
8dbbc384 560/* lock_file locks file FN,
8489eb67
RS
561 meaning it serves notice on the world that you intend to edit that file.
562 This should be done only when about to modify a file-visiting
563 buffer previously unmodified.
8dbbc384 564 Do not (normally) call this for a buffer already modified,
8489eb67
RS
565 as either the file is already locked, or the user has already
566 decided to go ahead without locking.
567
8dbbc384 568 When this returns, either the lock is locked for us,
8489eb67
RS
569 or the user has said to go ahead without locking.
570
8dbbc384 571 If the file is locked by someone else, this calls
8489eb67 572 ask-user-about-lock (a Lisp function) with two arguments,
8dbbc384 573 the file name and info about the user who did the locking.
8489eb67
RS
574 This function can signal an error, or return t meaning
575 take away the lock, or return nil meaning ignore the lock. */
576
8489eb67
RS
577void
578lock_file (fn)
eb4b1c05 579 Lisp_Object fn;
8489eb67 580{
f4a4528d 581 register Lisp_Object attack, orig_fn, encoded_fn;
8dbbc384
RS
582 register char *lfname, *locker;
583 lock_info_type lock_info;
3edc33a4 584 struct gcpro gcpro1;
8489eb67 585
33bae690
RS
586 /* Don't do locking while dumping Emacs.
587 Uncompressing wtmp files uses call-process, which does not work
588 in an uninitialized Emacs. */
589 if (! NILP (Vpurify_flag))
590 return;
591
5383bc6d 592 orig_fn = fn;
8af8a9ca 593 GCPRO1 (fn);
1e89de84 594 fn = Fexpand_file_name (fn, Qnil);
f4a4528d 595 encoded_fn = ENCODE_FILE (fn);
1e89de84 596
8dbbc384 597 /* Create the name of the lock-file for file fn */
f4a4528d 598 MAKE_LOCK_NAME (lfname, encoded_fn);
8489eb67 599
32676c08
JB
600 /* See if this file is visited and has changed on disk since it was
601 visited. */
8489eb67 602 {
a57bc488 603 register Lisp_Object subject_buf;
3036594f 604
5383bc6d 605 subject_buf = get_truename_buffer (orig_fn);
3036594f 606
265a9e55
JB
607 if (!NILP (subject_buf)
608 && NILP (Fverify_visited_file_modtime (subject_buf))
609 && !NILP (Ffile_exists_p (fn)))
8489eb67 610 call1 (intern ("ask-user-about-supersession-threat"), fn);
3036594f 611
8489eb67 612 }
8af8a9ca 613 UNGCPRO;
8489eb67
RS
614
615 /* Try to lock the lock. */
8dbbc384
RS
616 if (lock_if_free (&lock_info, lfname) <= 0)
617 /* Return now if we have locked it, or if lock creation failed */
8489eb67
RS
618 return;
619
620 /* Else consider breaking the lock */
266d7a00
RS
621 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
622 + LOCK_PID_MAX + 9);
79e51eeb 623 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
8dbbc384
RS
624 lock_info.pid);
625 FREE_LOCK_INFO (lock_info);
626
627 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
265a9e55 628 if (!NILP (attack))
8489eb67
RS
629 /* User says take the lock */
630 {
8dbbc384 631 lock_file_1 (lfname, 1);
8489eb67
RS
632 return;
633 }
634 /* User says ignore the lock */
635}
636
8489eb67
RS
637void
638unlock_file (fn)
639 register Lisp_Object fn;
640{
641 register char *lfname;
642
1e89de84 643 fn = Fexpand_file_name (fn, Qnil);
88eace34 644 fn = ENCODE_FILE (fn);
1e89de84 645
7b92975f 646 MAKE_LOCK_NAME (lfname, fn);
8489eb67 647
8dbbc384 648 if (current_lock_owner (0, lfname) == 2)
8489eb67 649 unlink (lfname);
8489eb67
RS
650}
651
652void
653unlock_all_files ()
654{
655 register Lisp_Object tail;
656 register struct buffer *b;
657
03699b14 658 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
8489eb67 659 {
03699b14 660 b = XBUFFER (XCDR (XCAR (tail)));
5757b805 661 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
1c343051
KH
662 {
663 register char *lfname;
664
665 MAKE_LOCK_NAME (lfname, b->file_truename);
666
667 if (current_lock_owner (0, lfname) == 2)
668 unlink (lfname);
669 }
8489eb67
RS
670 }
671}
8489eb67
RS
672\f
673DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
674 0, 1, 0,
675 "Lock FILE, if current buffer is modified.\n\
676FILE defaults to current buffer's visited file,\n\
677or else nothing is done if current buffer isn't visiting a file.")
e9319ef2
EN
678 (file)
679 Lisp_Object file;
8489eb67 680{
e9319ef2
EN
681 if (NILP (file))
682 file = current_buffer->file_truename;
8489eb67 683 else
e9319ef2 684 CHECK_STRING (file, 0);
6a140159 685 if (SAVE_MODIFF < MODIFF
e9319ef2
EN
686 && !NILP (file))
687 lock_file (file);
8489eb67
RS
688 return Qnil;
689}
690
691DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
692 0, 0, 0,
693 "Unlock the file visited in the current buffer,\n\
694if it should normally be locked.")
695 ()
696{
6a140159 697 if (SAVE_MODIFF < MODIFF
5757b805
RS
698 && STRINGP (current_buffer->file_truename))
699 unlock_file (current_buffer->file_truename);
8489eb67
RS
700 return Qnil;
701}
702
8489eb67
RS
703/* Unlock the file visited in buffer BUFFER. */
704
d07e0802 705void
8489eb67
RS
706unlock_buffer (buffer)
707 struct buffer *buffer;
708{
6a140159 709 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
5757b805
RS
710 && STRINGP (buffer->file_truename))
711 unlock_file (buffer->file_truename);
8489eb67
RS
712}
713
8105cbf7 714DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
8489eb67
RS
715 "Return nil if the FILENAME is not locked,\n\
716t if it is locked by you, else a string of the name of the locker.")
e9319ef2
EN
717 (filename)
718 Lisp_Object filename;
8489eb67 719{
8dbbc384 720 Lisp_Object ret;
8489eb67
RS
721 register char *lfname;
722 int owner;
8dbbc384 723 lock_info_type locker;
8489eb67 724
e9319ef2 725 filename = Fexpand_file_name (filename, Qnil);
8489eb67 726
e9319ef2 727 MAKE_LOCK_NAME (lfname, filename);
8489eb67 728
8dbbc384 729 owner = current_lock_owner (&locker, lfname);
8489eb67 730 if (owner <= 0)
8dbbc384
RS
731 ret = Qnil;
732 else if (owner == 2)
733 ret = Qt;
734 else
735 ret = build_string (locker.user);
736
737 if (owner > 0)
738 FREE_LOCK_INFO (locker);
739
740 return ret;
8489eb67 741}
32676c08
JB
742\f
743/* Initialization functions. */
744
a3fd58aa
KH
745void
746init_filelock ()
747{
748 boot_time = 0;
b97771fc 749 boot_time_initialized = 0;
a3fd58aa
KH
750}
751
dfcf069d 752void
8489eb67
RS
753syms_of_filelock ()
754{
5f8d6a10
RS
755 DEFVAR_LISP ("temporary-file-directory", &Vtemporary_file_directory,
756 "The directory for writing temporary files.");
757 Vtemporary_file_directory = Qnil;
758
8489eb67
RS
759 defsubr (&Sunlock_buffer);
760 defsubr (&Slock_buffer);
761 defsubr (&Sfile_locked_p);
762}
763
764#endif /* CLASH_DETECTION */