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